在服务器关闭连接之前,客户端不会收到响应消息(Java)

时间:2016-08-29 16:37:53

标签: java sockets tcp network-programming client-server

我的同事和我正在研究与Web服务通信的客户端应用程序,以便处理某些交易数据。这些是我们沟通的步骤:

  1. 客户端应用程序启动连接并发送请求消息(timestamp = T1
  2. Web服务接受连接并处理请求(timestamp ≈ T1
  3. Web服务返回响应消息(timestamp = T1 + few_seconds
  4. Web服务关闭连接(timestamp = T1 + 3_minutes
  5. 客户端应用程序获取响应消息并继续进行数据解析(timestamp = T1 + 3_minutes
  6. 我们的问题在于时间戳参考: Web服务处理请求并几乎立即检索响应,但客户端应用程序在服务器关闭连接之前不会收到响应消息。这是日志文件:

    客户端应用程序日志代码段:

    10:46:25,031 INFO  MessageHandler.java:115 Message sent.
    10:49:25,071 INFO  MessageHandler.java:125 Message received.
    10:49:25,103 DEBUG  MessageParser.java:67 Message parsed.
    

    服务器应用程序日志:

    10:46:25:153 <INFO>   Client connection accepted.
    ...
    10:46:26:602 <INFO>   Response message sent.
    ...
    10:49:25:069 <INFO>   Closing connection...
    

    如您所见,客户端仅在服务器关闭连接时才会收到响应。

    以下是完成通信的方法的客户端应用代码:

    public static String sendMsg(byte[] msg, String serverIp, int port) {
        try {
                InetAddress address = InetAddress.getByName(serverIp);
                Socket socket = new Socket(address, port);
                OutputStream os = socket.getOutputStream();
    
                logger.info("Message sent.");
    
                os.write(msg, 0, msg.length);
                os.flush();
    
                InputStream is = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(is);
                BufferedReader br = new BufferedReader(isr);
                String msgReceived = br.readLine();
    
                logger.info("Message received.");
                os.close();
                return msgReceived;
            } ...(catch blocks) ... 
    }
    

    假设我们无法更改Web服务实现,是否有办法在服务启动响应时立即在客户端获取响应消息(然后通过客户端关闭连接)?提前致谢。

3 个答案:

答案 0 :(得分:3)

最有可能的是,客户端没有正确实现消息协议。例如,客户端调用readLine。消息协议是否指定消息是?如果没有,readLine将一直等到连接关闭,仍然试图获取永远不会被发送的那条线。

除非客户端了解邮件的分隔方式,否则客户端将无法找到邮件的结尾。如何在协议中分隔消息?检测消息结束的客户端代码在哪里?如果你没有写它,它就不会发生。

答案 1 :(得分:1)

从客户端来看,你可能无法做到这一点。可能发生的是Web服务器正在缓冲来自Web服务的响应(因此它可以设置内容长度标题等),因此在Web服务关闭连接之前,不会发送任何数据。您可以使用br.read()方法间接测试此假设,以便像现在一样一次读取单个数据字符而不是整行。

答案 2 :(得分:1)

正如@Yeroc建议的那样,似乎Web服务器正在缓冲其响应,并且在发生某些超时之前不会刷新缓冲区。 (这在我看来是服务器端的一个糟糕的设计选择,但是如果你无法控制服务器,那么你可能会坚持使用它。)

我会尝试在客户端执行shutdown(SHUT_WR)。这应该产生一个&#34;文件的结尾&#34;服务器中的指示可能会导致它刷新缓冲区并关闭连接。由于这正是您想要发生的事情,因此可以更快地为您提供答案。带有shutdown的{​​{1}}仅关闭一个方向的连接 - 客户端到服务器的方向 - 因此您仍然可以接收响应。

(服务器可以在没有刷新的情况下选择SHUT_WR,但似乎可以将缓冲区作为高级close调用的副作用来完成在服务器端,所以它绝对值得一试。)