无限期的TCP数据包接收

时间:2017-12-22 14:29:27

标签: java windows sockets networking tcp

部署环境 我在Windows 10操作系统上使用JAVA创建了一个TCP服务器。我的TCP客户端程序是用VC ++编写的,可以在Windows 7操作系统上运行(我对这部分代码没有任何控制权,对我来说这是一个黑盒子)。

我的TCP服务器代码如下:

Socket s = ss.accept();
s.setReceiveBufferSize(2000);
s.setSendBufferSize(2000);
s.setTcpNoDelay(true);
s.setKeepAlive(true);
new TcpConnectionHandler(s,this.packetHandler); 

以下是TCP连接处理程序代码段:

InputStream incomingPacketBuffer = this.clientSocket.getInputStream();
OutputStream outgoingPacketBuffer = this.clientSocket.getOutputStream();
int bufferLen=0;
byte inBuffer[] = new byte[this.clientSocket.getReceiveBufferSize()];
byte outBuffer[] = new byte[this.clientSocket.getSendBufferSize()]; 
while(this.clientSocket.isConnected())
{
    bufferLen = incomingPacketBuffer.read(inBuffer);
    if(bufferLen>0)
    {
        outBuffer = (byte[]) this.packetHandlerModule.invoke(this.packetHandler,Arrays.copyOf(inBuffer, bufferLen));
    }
    if(outBuffer != null)
    {
        if(this.clientSocket.isConnected())
        {
            outgoingPacketBuffer.write(outBuffer);
            outgoingPacketBuffer.flush();
        }
    }
}
this.clientSocket.close();

通信是基于数据包的,协议/解析由packetHandler处理。

我尝试过另外两种变体:

  1. 我已经尝试在将回复发送回客户端时关闭套接字。也就是说,在收到一个数据包后,我回复客户端并关闭连接。

  2. 我在使用inputStream.available方法之前使用了read

  3. 我面临的问题:

    大多数情况下,TCP服务器会在一秒钟内回复传入的数据包。如果服务器在一些空闲时间之后收到数据包,则服务器不会回复数据包。有时即使正在进行活动通信,也不会传输回复。其次,即使客户端套接字关闭连接,isConnected函数也会返回true。

    调试尝试次数:

    1. 我使用teraterm发送数据包并进行检查。行为是一样的。只要我一个接一个地发送数据包,我就没有问题。如果一个数据包没有收到回复,那么之后发送的每个数据包都不会得到服务器的回复。

    2. 当我在服务器控制台中按Ctrl + C时,teraterm发送的所有数据包都由TCP服务器处理,并回复回复。在此之后,服务器可以正常工作一段时间。

    3. 我用wireshark检查了数据包流。当回复正常发回时,它与客户端请求的ACK一起发送(SYN,SYN + ACK,ACK,PSH,PSH + ACK,FYN,FYN + ACK,ACK)。当回复被修复时(可能不是正确的术语,它被卡在inputStream.available或inputStream.read中),服务器只发送ACK数据包(SYN,SYN + ACK,ACK,PSH,ACK)。

    4. 我在stackexchange中检查了很多论坛和其他线程,了解了Nagle的算法,应用程序必须处理TCP中的打包,TCP可能会收到10 + 10个数据包,如8 + 12或15 + 5或任何此类方式。服务器代码负责打包,setKeepAlive设置为true(从服务器发送数据包时没有问题)。

    5. 简而言之:“有时,即使有传入数据包,TCP读取呼叫也会被长时间阻止。按下Ctrl + C时,它们会被处理。”

      PS:我刚开始在stackexchange上发布查询,所以如果在制定查询方面存在任何问题,请告诉我。

      PPS:很抱歉这么长的帖子。

      更新

      1. 来自 EJB 的评论帮助我确定了对等断开连接。

      2. 我使用Ubuntu 16.04作为服务器操作系统进行了另一次设置。已经3天了,Windows系统偶尔会出现这个问题。 Ubuntu 16.04从未停滞过。

1 个答案:

答案 0 :(得分:0)

要考虑的一些事情;

  • TCP缓冲区大小通常至少为8K,我认为你不能将它们转换为2000字节,或者如果可以的话,我认为这不是一个好主意。
  • byte[]的大小在大约2K时并不重要,您也可以选择一个值。
  • 您不需要多次创建缓冲区。

所以总之我会尝试。

Socket s = ss.accept();
s.setTcpNoDelay(true);
s.setKeepAlive(true);
new TcpConnectionHandler(s,this.packetHandler);

try {
    InputStream in = this.clientSocket.getInputStream();
    OutputStream out = this.clientSocket.getOutputStream();
    int bufferLen = 0;
    byte[] buffer = new byte[2048];
    while ((bufferLen = in.read(buffer)) > 0) {
        out.write(buffer, 0, bufferLen); // not buffered so no need to flush
    }
} finally {
    this.clientSocket.close();
}
  

有时,即使有传入的数据包,TCP读取呼叫也会被长时间阻止。

编写一个测试Java客户端,看看这不是由于Java中的行为造成的。