TCP Socket / NetworkStream意外失败

时间:2015-07-03 13:47:05

标签: c# sockets tcp tcpclient networkstream

这特别是关于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)
{

}

2 个答案:

答案 0 :(得分:0)

您未正确测试关闭其连接结束的对等方。

从此链接:https://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.read%28v=vs.110%29.aspx?f=255&MSPPError=-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:

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块是空的。你会继续尝试接收。

答案 1 :(得分:0)

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

相关问题