【问题标题】:EOFException / SocketException when working with sockets and threads使用套接字和线程时出现 EOFException / SocketException
【发布时间】:2015-05-31 03:54:15
【问题描述】:

这个套接字应用程序工作得非常好,直到我添加对服务器的多个客户端连接的支持。然后我从客户端收到一个 EOFException,并从服务器收到一个 SocketException: Socket closed。

Server.java:

public class Server {

    static final int PORT = 8005;
    static final int QUEUE = 50;

    public Server() {
        while (true) {
            try (ServerSocket serverSocket = new ServerSocket(PORT, QUEUE);
                 Socket socket = serverSocket.accept();
                 DataInputStream input = new DataInputStream(socket.getInputStream());
                 DataOutputStream output = new DataOutputStream(socket.getOutputStream())) {

                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            output.writeUTF("Hey, this is the server!");
                            output.flush();
                            System.out.println(input.readUTF());
                        } catch (IOException e) {
                            System.out.println();
                            e.printStackTrace();
                        }
                    }
                });
                thread.start();

            } catch (IOException e) {
                System.out.println(e.getMessage());
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        new Server();
    }

}

Client.java:

public class Client {

    static final String HOST = "localhost";
    static final int PORT = 8005;

    public Client() {
        try (Socket socket = new Socket(HOST, PORT);
             DataInputStream input = new DataInputStream(socket.getInputStream());
             DataOutputStream output = new DataOutputStream(socket.getOutputStream())
        ) {
            System.out.println(input.readUTF());
            output.writeUTF("Hey, this is the client!");
            output.flush();
        } catch (IOException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new Client();
    }

}

【问题讨论】:

    标签: java multithreading sockets socketexception eofexception


    【解决方案1】:

    这里有几个问题:

    1. 您正在为每次循环创建一个新的ServerSocket。对于多客户端服务器,您应该改为打开一个 ServerSocket 并为每个连接的客户端调用 accept()
    2. 一旦退出try 块,Try-with-resources 就会关闭它提供的所有资源。您正在创建一个使用output 但独立于try 块执行的Thread,因此执行流程在thread 完成执行之前离开try 块,从而导致socket(和@987654331 @) 在线程能够使用它们之前被关闭。这是您的资源需要在try 块范围之外使用的情况之一(在您创建以使用它们的线程中),因此 try-with-resources 无法为您完成所有资源处理。

    我会将您的服务器代码重新排列为:

    public class Server {
    
        static final int PORT = 8005;
        static final int QUEUE = 50;
    
        public Server() {
            // create serverSocket once for all connections
            try (ServerSocket serverSocket = new ServerSocket(PORT, QUEUE)) {
                while (true) {
                    // accept a client connection, not in a try-with-resources so this will have to be explicitly closed
                    final Socket socket = serverSocket.accept();
    
                    Thread thread = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            // limit scope of input/output to where they're actually used
                            try (DataInputStream input = new DataInputStream(socket.getInputStream());
                                    DataOutputStream output = new DataOutputStream(socket.getOutputStream())) {
                                output.writeUTF("Hey, this is the server!");
                                output.flush();
                                System.out.println(input.readUTF());
                            } catch (IOException e) {
                                System.out.println();
                                e.printStackTrace();
                            }
    
                            // implicitly close socket when done with it
                            try {
                                socket.close();
                            } catch (IOException e) {
                                System.out.println();
                                e.printStackTrace();
                            }
                        }
                    });
                    thread.start();
                }
            } catch (IOException e) {
                System.out.println(e.getMessage());
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            new Server();
        }
    }
    

    对代码进行了一些注释以解释一些动作。另请注意,socket.close() 调用位于其自己的 try-catch 块中,以确保即使 I/O 流抛出异常也能调用它。它可以等效地(或者现在我想起来可能更正确)被放置在 I/O 流 try-catch 块上的 finally 块中。

    【讨论】:

      猜你喜欢
      • 2018-11-12
      • 1970-01-01
      • 1970-01-01
      • 2020-03-03
      • 2016-07-27
      • 2021-12-10
      • 2018-05-23
      • 2010-12-19
      • 2014-09-09
      相关资源
      最近更新 更多