新的ObjectInputStream导致挂起/超时

时间:2015-10-20 17:38:29

标签: java

我知道这个问题已经被问了好几次了。但是,在遵循所有其他问题的建议之后,我仍然不知道问题可能是什么。

我有服务器客户端。一个简单的ping / pong程序。在运行服务器然后运行客户端并给它一些时间来运行它之后,超时异常会不时地被抛出......

超时是为了防止阻塞,但是,如果删除,则会导致程序停止。

有没有办法防止这种情况发生?

Server.java

public static void main(String args[]) {
        try {
            ServerSocket serverSocket = new ServerSocket(3000);
            while (true) {
                Socket socket = serverSocket.accept();
                String message = null;
                try {
                    socket.setSoTimeout(3000);
                    try (ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream())) {
                        message = (String) objectInputStream.readObject();
                        System.out.println("Server received " + message);
                    }
                    socket.close();
                } catch (IOException | ClassNotFoundException ex) {
                    //This exception is thrown because it hangs, but why does it hang?
                    Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                }
                if ((message != null) && (message.equals("Ping"))) {
                    try {
                        Socket pongSocket = new Socket("localhost", 3000);
                        pongSocket.setSoTimeout(3000);
                        try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(pongSocket.getOutputStream())) {
                            objectOutputStream.writeObject("Pong");
                            objectOutputStream.flush();
                            System.out.println("Server sent Pong");
                        }
                        pongSocket.close();
                        continue;
                    } catch (IOException ex) {
                        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        } catch (IOException ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

Client.java

public static void main(String args[]) {
        while (true) {
            try {
                Socket pingSocket = new Socket("localhost", 3000);
                pingSocket.setSoTimeout(3000);
                try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(pingSocket.getOutputStream())) {
                    objectOutputStream.writeObject("Ping");
                    System.out.println("Client sent Ping");
                    objectOutputStream.flush();
                }
                pingSocket.close();
            } catch (IOException ex) {
                Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

2 个答案:

答案 0 :(得分:2)

您对服务器和客户端如何使用套接字感到困惑。您可以在stackoverflow上找到一堆示例,甚至可以通过Google找到更多示例,但一般的习惯用语是:

server:
    create server socket
    call accept on server socket
    with accepted socket
        read request from socket
        write response to socket
        close accepted socket
        loop back to accept

client:
    create socket
    call connect on socket
    write request to socket
    read response from socket
    close socket

(Java会自动为您做一些,例如,在创建套接字并指定主机和端口时,Socket类会为您调用connect。)

在您的服务器中,您在读取请求后关闭接受的套接字,然后创建并连接到新的套接字以发送响应,该响应将响应发送到localhost:3000上的任何内容,这是< em>您的服务器。此外,在您的客户端中,您正在编写请求,但没有读取响应,并且在紧密循环中这样做,因此您创建了很多与服务器的连接,这将很快填满接受积压。

真实的,生产应用程序会在服务器中使用线程,甚至使用更高级别的库甚至是像Tomcat这样的整个服务器,但在底层,他们基本上都在做上述事情,所以理解它是很好的。

为了演示,这就是您的代码应该是这样的:

<强> Server.java

public static void main(String args[]) {
    try {
        ServerSocket serverSocket = new ServerSocket(3000);
        while (true) {
            Socket socket = serverSocket.accept();
            socket.setSoTimeout(250);
            String message = null;
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
            try {
                message = (String) objectInputStream.readObject();
                System.out.println("server read: " + message);
            } catch (IOException | ClassNotFoundException ex) {
                Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
            }
            if ((message != null) && (message.equals("Ping"))) {
                try {
                    objectOutputStream.writeObject("Pong");
                    System.out.println("server sent pong");
                } catch (IOException ex) {
                    Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            objectInputStream.close();
            objectOutputStream.close();
            socket.close();
        }
    } catch (IOException ex) {
        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
    }
}

<强> Client.java

public static void main(String args[]) {
    while (true) {
        try {
            Socket socket = new Socket("localhost", 3000);
            String message;
            socket.setSoTimeout(250);
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject("Ping");
            System.out.println("client sent ping");
            try (ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream())) {
                message = (String) objectInputStream.readObject();
                System.out.println("client read: " + message);
            }
            objectOutputStream.close();
            socket.close();
        } catch (IOException | ClassNotFoundException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            Thread.sleep(10000);
        } catch (InterruptedException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

答案 1 :(得分:0)

你没有任何限制发送者的速度。一目了然,我会说你只是通过发送请求比处理它们更快来压倒服务器。你的服务器&#34;在套接字上收听不能与非受限制的&#34;客户进行竞争&#34;。