【问题标题】:Handling multi Java TCP clients with Threads使用线程处理多个 Java TCP 客户端
【发布时间】:2016-04-27 22:39:04
【问题描述】:

我一直在使用 TCP 服务器/客户端的东西。在连接多个客户端的多个用户时,我非常擅长 UDP 编程。我尝试在使用 Threads 制作的 TCP 服务器上做同样的事情,但是每当 Thread 访问这段代码时

String reader = (String)in.readObject();

产生了一个错误,线程停止执行代码,但线程仍然运行程序保持它活着。 无论如何,这里是整个源代码:

public class TestServer implements Runnable {

private Thread run, streams, connect, receive, send;

private ServerSocket socket;
private Socket conn;
private ObjectInputStream in;
private ObjectOutputStream out;

private boolean running, incomingMessage = false;
private int port;

public TestServer(int port) throws IOException {

    this.port = port;

    socket = new ServerSocket(port);

    console("Server stated on : " + InetAddress.getLocalHost() + " : " + port);

    run = new Thread(this, "Run");
    run.start();

}

public void run() {

    running = true;
    connect();
    receive();
}

private void connect() {

    connect = new Thread("Connect") {

        public void run() {

            while(running) {

                try {
                    conn = socket.accept();
                } catch (IOException e) {

                    e.printStackTrace();
                }

                console("You are now connected" + conn.getInetAddress().toString() + " : " + conn.getPort());

                try {
                    setupStreams();
                } catch (IOException e) {

                    e.printStackTrace();
                }

            }


        }

    }; connect.start();

}

private void setupStreams() throws IOException {

    streams = new Thread("Streams") {

        public void run() {

            try {

                console("Setting up Streams");

                out = new ObjectOutputStream(conn.getOutputStream());
                out.flush();

                in = new ObjectInputStream(conn.getInputStream());

                console("Streams are now setup");

                incomingMessage = true;
                receive.start();

            } catch(IOException e) {
                e.printStackTrace();
            }
        }

    }; streams.start();



}

private void receive() {

    receive = new Thread("Receive") {

        public void run() {

            while(incomingMessage) {

                String message = "";

                try {

                    message = (String) in.readObject();
                    //This is the only flaw the program

                } catch (ClassNotFoundException | IOException e) {

                    e.printStackTrace();
                }

                console("Client : " + message);
            }
        }

    };
}

private void console(String message) {
    System.out.println(message);
}

public static void main(String[] args) {
    try {
        new TestServer(1234);
    } catch (IOException e) {

        e.printStackTrace();
    }
}

}

仅供参考,我对此并不陌生。该错误是因为即使没有要接收的数据包,服务器也开始接收数据包。但是因为线程强制它接收它,所以我在线程中生成错误并且不知道任何其他方法来解决这个问题。所以请帮忙。提前致谢。

【问题讨论】:

  • incomingMessage 除了在初始化程序中之外,永远不会设置为 false,因此 while 循环无法结束。
  • 定义'产生错误'。

标签: java tcp server client


【解决方案1】:

每个连接不应需要 2 个线程。只需要一个线程。接受连接后,将其传递给工作线程以开始读取。这可以在工作线程的 while 循环中完成。

尽管可以读取套接字的输入流,但 ObjectInputStream() 类更敏感。如果有任何错误,则其状态已损坏,无法使用。

    while (true) {
        try {
            Object input = in.readObject();
            message = (String) input;
        } catch (IOException e) {
            e.printStackTrace();
            break; //unrecoverable
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            break; //unrecoverable
        }

        console("Client : " + message);
    }

使用特定的消息协议而不是发送序列化的 Java 对象是一种更好的设计。例如,如果您要发送与示例类似的字符串,则可以使用 InputStreamReader 更轻松地将字节转换为字符,并且错误处理更少。

这些资源会对您有所帮助:

https://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html#later

Java - Listening to a socket with ObjectInputStream

ObjectInputStream(socket.getInputStream()); does not work

【讨论】:

  • 谢谢兄弟,至少我现在有了一个起点。
  • 读取循环不正确。 readObject() 在流结束时不会返回 null:它会抛出 EOFException. Null 可以出现在流中的任何位置,不应被视为终止标记。
  • @EJP 你是对的。我查看了 Java 源代码。看来您必须阅读直到出现异常...
  • 创建一个新的ObjectInputStream 不会解决流损坏问题。什么都不会。您对break 声明有异议?
  • @EJP 感谢您的评论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-27
  • 2021-04-09
  • 1970-01-01
  • 2018-04-28
  • 2012-09-26
  • 2013-09-05
  • 1970-01-01
相关资源
最近更新 更多