TCP套接字/NetworkStream意外失败

本文关键字:意外 失败 NetworkStream 套接字 TCP | 更新日期: 2023-09-27 18:01:06

这是一个关于NetworkStream通过TCP消耗原始数据的后台通信中发生了什么的问题。TcpClient连接直接与网络上的硬件设备通信。每隔一段时间,NetworkStream就会随机出现问题,在调试模式下观察时可以最好地描述它。我在流上设置了一个读取超时,当一切按预期工作时,当跨过Stream.Read时,它将在那里等待传入数据的超时时间长度。否则,只有一小部分数据通过,TcpClient仍然显示为打开和连接,但Stream.Read不再等待传入数据的超时时间。它立即转到下一行,显然没有收到任何数据,在所有东西都被处理掉并重新建立新的连接之前,任何数据都不会通过。

问题是,在这个特定的场景中,NetworkStream此时处于什么状态,是什么原因导致它,以及为什么TcpClient连接仍然处于看似打开和有效的状态?背景中发生了什么?没有抛出和捕获错误,流是否在后台静默失败?TcpClient和NetworkStream的状态之间有什么区别?

private TcpClient Client;  
private NetworkStream Stream;  
Client = new TcpClient();  
var result = Client.BeginConnect(IPAddress, Port, null, null);  
var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(2));  
Client.EndConnect(result);  
Stream = Client.GetStream();  
try  
{  
    while (Client.Connected)  
    {  
        bool flag = true;
        StringBuilder sb = new StringBuilder();
        while (!IsCompleteRecord(sb.ToString()) && Client.Connected)
        {
            string response = "";
            byte[] data = new byte[512];
            Stream.ReadTimeout = 60000;
            try
            {
                int recv = Stream.Read(data, 0, data.Length);
                response = Encoding.ASCII.GetString(data, 0, recv);
            }
            catch (Exception ex)
            {
            }
            sb.Append(response);
        }
        string rec = sb.ToString();
        // send off data
        Stream.Flush();
    }
}
catch (Exception ex)
{
}

TCP套接字/NetworkStream意外失败

您没有正确测试对等端关闭连接的情况。

通过此链接:https://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.read%28v=vs.110%29.aspx?f=255&MSPP错误=-2147217396
This method reads data into the buffer parameter and returns the number of bytes successfully read. If no data is available for reading, the Read method returns 0. The Read operation reads as much data as is available, up to the number of bytes specified by the size parameter. If the remote host shuts down the connection, and all available data has been received, the Read method completes immediately and return zero bytes.

你只是在做stream.read,而不是解释你可能收到了0个字节的事实,这意味着对等端关闭了它的连接端。这被称为半封闭。它不会再发送给你了。在这一点上,你也应该关闭你的插座末端。

这里有一个可用的示例:
https://msdn.microsoft.com/en-us/library/bew39x2a(v=vs.110(.aspx

// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0) {
    // There might be more data, so store the data received so far.
    state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead));
    // Get the rest of the data.
    client.BeginReceive(state.buffer,0,StateObject.BufferSize,0,
                new AsyncCallback(ReceiveCallback), state);
} else {
    // All the data has arrived; put it in response.
    if (state.sb.Length > 1) {
         response = state.sb.ToString();
    }
    // Signal that all bytes have been received.
    receiveDone.Set(); ---> not that this event is set here
}

并且在主代码块中它正在等待接收完成:

receiveDone.WaitOne();
// Write the response to the console.
Console.WriteLine("Response received : {0}", response);
// Release the socket.
client.Shutdown(SocketShutdown.Both);
client.Close();

结论:检查是否接收到0字节,并关闭套接字的一端,因为另一端就是这样做的。

超时处理时出现异常。由于catch块是空的,所以您实际上并没有在超时的情况下执行任何操作。你会继续尝试接收。

@Philip已经回答了这个问题
我只想补充一点,我建议使用SysInternal-TcpView,它基本上是netstat的GUI,可以让您轻松检查计算机的所有网络连接的状态
关于程序中连接状态的检测,请参阅SO.