【问题标题】:Java client-server / one thread multiple clientsJava客户端-服务器/一线程多客户端
【发布时间】:2012-04-25 14:35:41
【问题描述】:

首先,我不太确定如何解释,以免听起来令人困惑,所以我会尽量简化。作为两人游戏的一部分,我有一个服务器应用程序将两个客户端“配对”在一起。发生的方式是,当第一个客户端连接到服务器时,接受套接字连接,使用该客户端创建一个新的 ClientProtocol 线程但未启动。当另一个客户端连接到服务器时,他被添加到前一个线程中,然后启动该线程。线程知道两个输入流和两个输出流,每个客户端一个。但是,当我尝试从客户端或服务器端读取时,什么都没有发生。这适用于单个线程中的单个客户端。这是一些代码:

服务器端(主线程)

public static Queue<ContestProtocol> contesters;

public static void main(String[] args) throws IOException {
    ServerSocket serverSocket = null;
    contesters = new LinkedList<ContestProtocol>();

    try {
        serverSocket = new ServerSocket(4444);
    } catch (IOException e) {
        System.err.println("Could not listen on port: 4444.");
        System.exit(-1);
    }

    while (true) {
        Socket socket = serverSocket.accept();

        ObjectInputStream ois;
        ObjectOutputStream oos;

        try {
            ois = new ObjectInputStream(socket.getInputStream());
            oos = new ObjectOutputStream(socket.getOutputStream());

            synchronized (contesters) {
                if (contesters.size() == 0) {
                    Contester contester1 = new contester(ois, oos);
                    contesters.add(new ContestProtocol(contester1));
                } else {
                    Contester contester2 = new Contester(ois, oos);
                    contesters.poll().hook(contester2).start();
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

服务器端(竞赛协议)

private Contester contester1, contester2;

public ContestProtocol(Contester contester1) {
    super("ContestProtocol");
}

public ContestProtocol hook(Contester contester2) {
    this.contester2 = contester2;
    return this;
}

public void run() {
    try {
        contester1.getOOS().writeInt(-1);
        contester2.getOOS().writeInt(-2);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

服务器端(参赛者):

public Contester(ObjectInputStream ois, ObjectOutputStream oos) {
    this.ois = ois;
    this.oos = oos;
}

public ObjectInputStream getOIS() {
    return ois;
}

public ObjectOutputStream getOOS() {
    return oos;
}

客户端:

try {
            socket = new Socket(serverAddr, 4444);
            oos = new ObjectOutputStream(socket.getOutputStream());
            ois = new ObjectInputStream(socket.getInputStream());
            int selectedChampion = ois.readInt();
} catch (Exception e) {
                e.printStackTrace();
}

ContestProtocol 线程完成执行没有问题,但两个客户端都挂在 readInt() 上。我不明白为什么。

【问题讨论】:

  • 我不确定我是否喜欢你处理这个的方式,但是,两个客户应该得到这些整数。 Wireshark 说什么?数据是否从服务器出去?
  • 经过一些测试,似乎某些线程必须相互阻塞。对 ois.available() 的调用将在调试器中挂起。
  • 哦,我预计您的设计无法正常工作,但尽管如此,客户端应该在服务器锁定某些读取调用之前获得它们的整数。

标签: java multithreading client


【解决方案1】:

这在访问资源时必须做互斥或信号量问题: 您正在使用的流(在这种情况下是输出流和输入流)正在读取和写入相同的资源。 因为所有这些进程都发生在一个继续的线程上,所以它们的线程相互中断,并在另一个线程上创建等待进程。
一种解决方案是,您在流对象上注册事件监听器,这样每当一个完成时,另一个才会启动。

【讨论】:

  • 没有流从线程的开始到结束保持活动状态。如果我关闭一个流,我会关闭套接字。
  • 据我所知,我不确定我是否理解您所说的“正在读取和写入同一资源”,objectInputStream 和 ObjectOutputStream 正在写入和读取两个不同的套接字。如果我有一个客户端来回读写服务器,它就可以工作。不过我可能弄错了。
  • 我只是忘了在这里调用flush(): public void run() { try { Competitioner1.getOOS().writeInt(-1);竞赛者1.getOOS().flush();竞赛者2.getOOS().writeInt(-2);竞赛者2.getOOS().flush(); } 捕捉(异常 e){ e.printStackTrace(); } }
  • 是的,flush() 就是交易!如果你在没有调用 flush() 的情况下关闭流,则不会写入任何内容。
【解决方案2】:

你应该循环你的客户端输入流。

while(true){
if(ois.avaible() > 0)
ois.readInt();
}

提示:使用 netty 研究异步网络以获得更好的性能。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-09
    • 1970-01-01
    • 1970-01-01
    • 2014-12-21
    • 2011-04-28
    • 1970-01-01
    • 2016-04-09
    • 1970-01-01
    相关资源
    最近更新 更多