TCP Socket/NetworkStream 意外失败
TCP Socket/NetworkStream Unexpectedly Failing
这是一个关于通过 TCP 使用原始数据的 NetworkStream 的后台通信中发生了什么的问题。 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)
{
}
您没有正确测试关闭其连接端的对等方。
由此 link : 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 块是空的。您将继续尝试接收。
@Philip 已经回答了你的问题。
我只想补充一点,我推荐使用 SysInternals TcpView,它基本上是 netstat 的 GUI,可以让您轻松检查计算机所有网络连接的状态。
关于程序中连接状态的检测,参见here in SO。
这是一个关于通过 TCP 使用原始数据的 NetworkStream 的后台通信中发生了什么的问题。 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)
{
}
您没有正确测试关闭其连接端的对等方。
由此 link : 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 块是空的。您将继续尝试接收。
@Philip 已经回答了你的问题。
我只想补充一点,我推荐使用 SysInternals TcpView,它基本上是 netstat 的 GUI,可以让您轻松检查计算机所有网络连接的状态。
关于程序中连接状态的检测,参见here in SO。