创建echo服务器 - 服务器只能响应一次

时间:2014-09-24 07:52:10

标签: java multithreading response echo-server

我正在创建一个多线程聊天服务器,它应该为每个连接的客户端创建一个单独的线程。每次客户端连接时,我的服务器都会创建一个客户端处理程序类的新实例,该实例应该跟踪来自/到该特定客户端的输入和传出消息。

客户端第一次连接到我的echo服务器时,服务器将响应客户端响应的回显。但是,如果我尝试第二次向服务器发送消息,则客户端会创建IOException。我自己创建了客户端应用程序,但我知道它有效,因为我可以很好地与其他服务器通信。我很确定问题是在这个客户端处理程序类的run方法中的某个地方,但我无法弄清楚它为什么不起作用。这是我的客户端处理程序类中的run方法:

public void run() {
    try (
        BufferedReader in =
                new BufferedReader(
                    new InputStreamReader(clientSocket.getInputStream()));

        PrintWriter out = 
            new PrintWriter(clientSocket.getOutputStream());
    ) {
        long time = System.currentTimeMillis();         
        out.println("Server - " + time + ": " + in.readLine());

        out.close();

        try {
            in.close();
        } catch (IOException e) {
            System.err.println("Couldn't close input stream");
        }
    } catch(IOException e) {
        System.err.println("Got an IOException error while reading or writing from/to client");
    }
}

我猜想我应该在某个地方有某种while循环,但是我实现这一切的所有尝试都失败了。例如。我试图更改此代码:

long time = System.currentTimeMillis();         
out.println("Server - " + time + ": " + in.readLine());

对此:

String inputLine;
while((inputLine = in.readLine()) != null) {
    long time = System.currentTimeMillis();         
    out.println("Server - " + time + ": " + inputLine);
}

这个解决方案或多或少是oracle网站(http://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html)表示它应该如何完成的副本。

我认为主要问题可能是我并没有真正掌握服务器/客户端通信的整体概念,因此非常感谢正确推动。

提前致谢!

1 个答案:

答案 0 :(得分:0)

您提到的Oracle文章中的重要部分是标题为“支持多个客户端”的部分。

基本的Java套接字API是一个阻塞API,它基本上意味着您调用一个方法,该方法会阻塞,直到发生IO事件。如果您需要等待多个IO事件 - 在您的情况下是传入的客户端连接和传入的数据 - 您必须创建多个线程。

本文中显示的服务器只接受单个incomming(客户端)连接,并在客户端关闭后关闭,因为服务器上的InputStream将返回null,导致循环终止。

首先,您的服务器需要看起来像这样(简化示例):

try (ServerSocket serverSocket = new ServerSocket(portNumber))
{
  while (running)
  {
    Socket clientSocket = serverSocket.accept();
    new Thread(new ClientHandler(clientSocket)).start();
  }
}   

注意:为每个客户端连接启动一个线程证明了这一点,但是在管理服务器上的连接负载方面有很大的简化。

客户端代码可以保持原样。

正如我所指出的那样,基础知识将线程管理留给了开发人员 - 这通常会导致麻烦,因为人们只是弄错了。由于这个Java的套接字API已经扩展到创建NIO API - Jakob Jenkov写了一些好tutorials

同样值得关注的是Netty,我个人认为比NIO更容易使用。