【问题标题】:why the TCP receiver can receive data after the Socket Server has shut down?为什么 Socket Server 关闭后 TCP 接收方可以接收数据?
【发布时间】:2011-05-18 21:08:56
【问题描述】:

我正在使用 Java 来实现一个多线程 TCP 服务器-客户端应用程序。但是现在我遇到了一个奇怪的问题:当我关闭服务器套接字时,接收器仍然可以连续接收到最后发送的数据包。由于套接字读取的细节是内核关注的问题,我无法弄清楚原因。有人可以给出一些指导吗? 提前致谢! 编辑: 涉及的代码很简单:

public void run() {
  while(runFlag) {
      //in = socket.getSocketInputStream();
      //byte[] buffer = new byte[bufferSize]; 
      try {
          in.read(buffer);
          //process the buffer;
      }catch(IOException e) {
          //
      }
  }
}

当关闭服务器套接字时,这个读操作会连续接收数据包(每次进入while循环)。

【问题讨论】:

    标签: java sockets networking io


    【解决方案1】:

    如果数据已经在客户端套接字的缓冲区中(内核级别,等待您的应用程序将其读取到用户空间内存中),则服务器无法阻止它被读取。就像蜗牛邮件一样:一旦发送出去,就无法撤消。

    【讨论】:

    • 如果数据已经在 sender 的套接字缓冲区中,它仍然会在 FIN 之前发送。
    • 这是一个单个位,表示这是此连接的最终数据包。
    【解决方案2】:

    操作系统内的 TCP/IP 堆栈缓冲连接两端的数据。发送方填充其 socket 发送缓冲区,设备驱动程序将数据包推送到线路上,该缓冲区会被耗尽。接收器在 socket 接收缓冲区 中累积数据包,该缓冲区被应用程序读取耗尽。

    【讨论】:

    • 感谢@ThiefMaster、@Nikolai N Fetissov 的快速而有帮助的回复。似乎问题发生在客户端的缓冲区中。但我仍然不太清楚为什么。(为什么 in.read(buffer) 不消耗内核缓冲区?)
    • 连接将处于半开状态,这是一个有效状态。
    【解决方案3】:

    这就是 TCP 的工作原理。这是一个可靠的字节流。未交付的数据在正常关闭后继续交付。这不是你想要的吗?为什么这是一个“问题”?

    【讨论】:

    • 对不起,如果我没有说清楚。通过“问题”,我的意思是客户端的读取操作将成功地不断读取最后发送的数据包(我认为阻止读取或抛出异常而不是每次都获取相同的数据包是有意义的)。我已经编辑了我的问题,也许你可以看看。
    • 这里的错误是你忽略了 in.read() 的结果。如果它返回-1,则对等方已关闭连接,因此您必须关闭套接字并退出循环。您还忽略了缓冲区未满的可能性,这将由 read() 小于 buffer.length 的正返回值指示,因此您的代码无论如何都不会工作。
    • 非常感谢!这真的很有帮助。忽略 read() 的返回值是我的错。但我试图做的是利用 read() 抛出的异常来指示网络状态并控制程序的工作流程。根据 java API 文档,如果检测到流结束,read() 将返回 -1 并抛出 IOException “如果由于文件末尾以外的任何原因无法读取第一个字节,如果输入流已关闭,或者如果发生其他一些 I/O 错误”。如果我关闭服务器,为什么我的代码中的 read() 不会引发任何异常?
    • 因为返回-1,表示检测到流的结尾。
    • @Xu DXn:“文件结束”是服务器关闭时发生的情况,所以没有例外 - 只是返回值 -1。
    猜你喜欢
    • 1970-01-01
    • 2012-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-17
    • 2012-10-24
    • 2012-06-09
    • 2020-05-28
    相关资源
    最近更新 更多