2015-10-20 42 views
0

我知道这个问题已被问了好几次了。然而,在遵循所有其他问题的建议之后,我仍然坚持问题是什么。新ObjectInputStream导致挂起/超时

我有一个服务器客户端。一个简单的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); 
      } 
     } 
    } 
+0

除了冲水()ANS迅速一部分,看看这个问题:http://stackoverflow.com/questions/33106127/swift-socket-readline-writeline/33106252#3310 6252。一旦serverSocket.accept()调用创建一个新的Socket,我更愿意创建一个线程来处理IO。创建一个线程并传递客户端Socket并在那里执行你的IO –

回答

2

您对服务器和客户端如何使用套接字感到困惑。你也许可以找到一堆的计算器和例子甚至可以通过谷歌更多,但总的成语是:

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 for you。)

在您的服务器中,您在读取请求后关闭接受的套接字,然后创建并连接到新的套接字以发送将要发送的响应localhost:3000上的任何监听的响应,这是您的服务器的。另外,在你的客户端,你正在写请求,但没有读取响应,并且在一个紧密的循环中这样做,所以你创建了很多连接到你的服务器,这将很快填补接受积压。

真正的生产应用程序会在服务器中使用线程,甚至使用更高级别的库或甚至像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); 
     } 
    } 
} 
+0

那么解决方案是什么? – Hooli

+0

这不仅仅是一个简单的修复,你需要修改你的代码才能像上面那样工作。例如,在Server.java中,读取请求后,请不要立即关闭套接字,然后打开一个新套接字。相反,请检查请求,然后发送适当的响应,然后关闭套接字并循环回接受。 – blm

+0

@ravindra感谢您做的研究,我手里挥着“你可能会找到一堆例子”。 :-)我在这里搜索过,但我在搜索中指定了Java,并且您指出的答案是关于Swift的问题,尽管答案是一个很好的一般答案,所以值得一看。 – blm

0

你有什么节流您的发件人的速度。一眼就可以判断,我认为你只是通过发送请求的速度超过可以处理的速度来压倒服务器。监听套接字的“服务器”无法与非阻塞的“客户端”竞争。