设置超时的套接字有时会在读取时停止

时间:2011-09-26 16:43:41

标签: java sockets

我有一个Java客户端(Windows XP上的1.6b17,通过Java webstart启动),它使用TCP套接字通过ADSL连接查询基于Java的服务器。客户端套接字具有超时设置(3000毫秒)。

偶尔(并且到目前为止,不可重复),客户端在从服务器读取响应时停止。有几百个安装,大多数用户大多数时间都没有遇到这个问题。

客户端按照以下步骤为每个请求创建一个新套接字:

  1. 创建一个新的套接字,将超时设置为3000毫秒
  2. 提交请求(单行文本)
  3. 读取多行响应,在收到特殊的“消息结束”序列时关闭套接字(或为null)
  4. 这里有一些(简化的)代码来说明:

    socket = new Socket(host, port);
    socket.setSoTimeout(socketTimeout);
    
    out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
    in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    
    socket.write(cmd);
    
    while (true) {
    
       line = in.readLine();
    
       if (line == null) break; 
    
       if (line.equals("EOL")) break;
    
       // Store line of text in an ArrayList
    }    
    
    socket.close();
    

    问题在于,偶尔在接收过程中,客户端将暂停最多5分钟,然后在没有任何干预的情况下恢复。在此之后,应用程序恢复,没有明显的性能问题。

    登录服务器端表示操作大约需要150毫秒,尽管有问题的时间戳是在关闭套接字之前采取的(我将尝试解决这个问题)。

    我的一个假设是,这不是由于网络问题,否则readLine会超时,这是一个有效的假设吗?

    这似乎也不太可能与垃圾收集相关。该应用程序有512MB分配给堆,而被检索的数据包含大约1600行100个字符。我的期望是,如果与GC或内存泄漏有关的问题是性能普遍下降而不是我所看到的那种“粘性”行为,这是正确的吗?

    非常感谢任何建议的故障排除策略。

    谢谢, 菲尔

2 个答案:

答案 0 :(得分:2)

我没有看到你达到5分钟的“暂停”。我只能想象你在数据包上得到了很多重试。你应该能够通过wireshark看到类似的东西。它可以为你提供其他东西的线索。

512 MB堆上的完整GC暂停时间应为0.5秒左右(非常接近)


如果您的连接不可靠,我建议您不要使用PrintWriter。如果它获得IOException,它会设置一个标志而不是抛出异常。如果你继续使用它,它什么都不做。

答案 1 :(得分:1)

readLine()应该超时。在任何平台上都没见过不行。也许你一次只收到一个角色,间隔不到3秒。 Wireshark会告诉你。

或者当你正在读行时,服务器可能没有在正确的位置发送换行符?