Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java TCP数据包接收的不确定状态_Java_Windows_Sockets_Networking_Tcp - Fatal编程技术网

Java TCP数据包接收的不确定状态

Java TCP数据包接收的不确定状态,java,windows,sockets,networking,tcp,Java,Windows,Sockets,Networking,Tcp,解聚环境: 我已经在Windows10操作系统上使用JAVA创建了一个TCP服务器。我的TCP客户端程序是用VC++编写的,运行在Windows7操作系统上(我对这部分代码没有任何控制权,它对我来说是一个黑匣子) 我的TCP服务器代码如下: Socket s = ss.accept(); s.setReceiveBufferSize(2000); s.setSendBufferSize(2000); s.setTcpNoDelay(true); s.setKeepAlive(true); new

解聚环境: 我已经在Windows10操作系统上使用JAVA创建了一个TCP服务器。我的TCP客户端程序是用VC++编写的,运行在Windows7操作系统上(我对这部分代码没有任何控制权,它对我来说是一个黑匣子)

我的TCP服务器代码如下:

Socket s = ss.accept();
s.setReceiveBufferSize(2000);
s.setSendBufferSize(2000);
s.setTcpNoDelay(true);
s.setKeepAlive(true);
new TcpConnectionHandler(s,this.packetHandler); 
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();
以下是TCP连接处理程序片段:

Socket s = ss.accept();
s.setReceiveBufferSize(2000);
s.setSendBufferSize(2000);
s.setTcpNoDelay(true);
s.setKeepAlive(true);
new TcpConnectionHandler(s,this.packetHandler); 
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
处理

我又尝试了两种变体:

Socket s = ss.accept();
s.setReceiveBufferSize(2000);
s.setSendBufferSize(2000);
s.setTcpNoDelay(true);
s.setKeepAlive(true);
new TcpConnectionHandler(s,this.packetHandler); 
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();
  • 我已尝试在回复发送回客户端时关闭套接字。也就是说,在收到一个数据包后,我回复客户机并关闭连接

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

  • 我面临的问题:

    Socket s = ss.accept();
    s.setReceiveBufferSize(2000);
    s.setSendBufferSize(2000);
    s.setTcpNoDelay(true);
    s.setKeepAlive(true);
    new TcpConnectionHandler(s,this.packetHandler); 
    
    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();
    
    大多数情况下,TCP服务器会在一秒钟内回复传入的数据包。如果服务器在空闲时间后收到数据包,则服务器不会回复该数据包。有时,即使正在进行主动通信,也不会发送回复。其次,
    isConnected
    函数返回true,即使客户端套接字关闭了连接

    调试尝试:

    Socket s = ss.accept();
    s.setReceiveBufferSize(2000);
    s.setSendBufferSize(2000);
    s.setTcpNoDelay(true);
    s.setKeepAlive(true);
    new TcpConnectionHandler(s,this.packetHandler); 
    
    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();
    
  • 我使用teraterm发送数据包并进行检查。行为是一样的。只要我一个接一个地发送数据包,我就没有问题。如果一个数据包没有得到回复,那么此后发送的每个数据包都不会得到服务器的回复

  • 当我在服务器控制台中按Ctrl+C时,TCP服务器将处理从teraterm发送的所有数据包,并返回reply。在此之后,服务器将在一段时间内正常工作

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

  • 我检查了stackexchange中的许多论坛和其他线程,了解了Nagle的算法,应用程序必须注意TCP中的打包,TCP可能会以8+12或15+5等方式接收10+10个数据包。服务器代码负责打包,
    setKeepAlive
    设置为true(从服务器发送数据包时没有问题)

  • 简而言之,问题是:“有时,即使有传入的数据包,TCP读取调用也会被长时间阻止。当按下Ctrl+C时,它们会被处理。”

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

    PPS:很抱歉这么长的帖子

    更新

  • 来自EJB的注释帮助我识别了对等断开连接

  • 我用Ubuntu 16.04作为服务器的操作系统进行了另一次设置。已经3天了,windows系统偶尔出现问题。Ubuntu 16.04从未过时


  • 有些事情要考虑;
    • TCP缓冲区的大小通常至少为8K,我不认为可以将它们压缩到2000字节,或者如果可以,我认为这不是一个好主意
    • 字节[]
      的大小在2K左右并不重要,您不妨选择一个值
    • 您不需要多次创建缓冲区
    总之,我会尝试

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

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


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

    isConnected()
    在测试时不可能为false。这不是对对等断开连接的测试,但是
    read()
    返回的-1是,您忽略了它。@EJB,谢谢。这有助于我正确地关闭连接。我相信这对您有所帮助,但您的问题代码中没有反映这一点。“无限期过期”是什么意思?客户端向服务器发送了一个数据包。服务器上的Wireshark显示正在发送回客户端的ack。但尚未收到答复。在调试模式下,我知道read调用从未返回。如果我在命令提示符下按Ctrl+C,则读取返回,并且正在处理数据包。我在Ubuntu 16.04上运行了另一个服务器实例,到目前为止我还没有遇到任何问题。我的要求是它应该在Windows系统中运行。谢谢你的输入。我知道不需要每次都创建缓冲区。但主要问题仍然存在。我的数据包的最大大小限制为200字节,因此到目前为止2k足以处理。正如我已经提到的,我使用teraterm使用TCP协议连接到我的服务器。还有,在随机的时间里,我得到了这个区块。我想这里的键是终端中的Ctrl+C。当我中断终端时,数据包会得到服务。@Raavanan上面的代码应该做你想做的事情,在这种情况下,我会编写一个java客户端来证明这一点。我不知道你们的终端程序是否有异常。问题不在于终端,我已经用终端检查了其他案例。无论如何,我想操作系统也会带来一些不同。请查看更新。