[英]NetworkStream callback called multiple times on server when client closes connection
I'm writing a simulator to test (de-)serialization of objects and sending them over TCP. 我正在编写一个模拟器来测试对象的反序列化,并通过TCP发送它们。 I use TcpClient, TcpListener and NetworkStreams in C# to communicate.
我在C#中使用TcpClient,TcpListener和NetworkStreams进行通信。 I want to open a connection, send multiple messages and after some time close the connection.
我想打开一个连接,发送多条消息,一段时间后关闭连接。 Establishing a connection and sending packets in both directions works fine.
建立连接并双向发送数据包效果很好。 However when i close the connection on the client (call
stream.Close()
and tcpClient.Close()
) the server's callback for BeginRead is called again and again. 但是,当我关闭客户端的连接(调用
stream.Close()
和tcpClient.Close()
)时,一次又一次调用BeginRead的服务器回调。
The client code: 客户端代码:
private TcpClient client;
public void StartClient()
{
this.client = new TcpClient(this.serverAddress, this.port);
}
public void Send(byte[] data)
{
var stream = this.client.GetStream();
stream.Write(data, 0, data.Length);
}
public void StopClient()
{
this.client.GetStream().Close();
this.tcpClient.Close();
}
The server code: 服务器代码:
private readonly AutoResetEvent autoResetEvent= new AutoResetEvent(false);
private TcpListener tcpListener;
public event Action<byte[]> MessageReceived;
public void StartListening()
{
this.tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 1337);
this.tcpListener.Start();
this.tcpListener.BeginAcceptTcpClient(this.ClientConnecting, this.tcpListener);
}
private void ClientConnecting(IAsyncResult result)
{
var listener = (TcpListener)result.AsyncState;
this.tcpClient = listener.EndAcceptTcpClient(result);
this.Listen();
}
private void Listen()
{
var stream = this.tcpClient.GetStream();
var buffer = new byte[256];
while (stream.CanRead)
{
try
{
stream.BeginRead(buffer, 0, buffer.Length, this.DataReceiveCallback, new ReceiveState { Buffer = buffer, Stream = stream });
}
catch
{
this.StopListening();
break;
}
this.autoResetEvent.WaitOne();
}
}
public void StopListening()
{
var stream = this.tcpClient.GetStream();
stream.Close();
this.tcpClient.Close();
this.tcpClient = null;
}
private void DataReceiveCallback(IAsyncResult ar)
{
var state = (ReceiveState)ar.AsyncState;
var stream = state.Stream;
if (stream.CanRead)
{
var buffer = state.Buffer;
var numberOfBytesRead = stream.EndRead(ar);
if (this.MessageReceived != null)
{
if (!stream.DataAvailable)
{
this.MessageReceived(buffer.Take(numberOfBytesRead).ToArray());
}
else
{
var receivedBytes = new List<byte>(buffer);
while (stream.DataAvailable)
{
numberOfBytesRead = stream.Read(buffer, 0, buffer.Length);
receivedBytes.AddRange(buffer.Take(numberOfBytesRead));
}
this.MessageReceived(receivedBytes.ToArray());
}
}
}
this.autoResetEvent.Set();
}
When I call StopClient()
on the client, the callback ( DataReceiveCallback
) on the server is being invoked. 当我在客户端上调用
StopClient()
时,正在调用服务器上的回调( DataReceiveCallback
)。 stream.CanRead
returns true, but there are 0 bytes to read. stream.CanRead
返回true,但是有0个字节要读取。 Also stream.DataAvailable
is false. 同样
stream.DataAvailable
为false。
However, apart from that, I see no way to know on the server side, that the client closed the connection. 但是,除此之外,我看不到在服务器端知道客户端关闭了连接。 And it is possible to receive 0 bytes from the client when the connection is still open.
当连接仍然打开时,可以从客户端接收0字节。
What happens as af now, is that after closing the connection on the client, DataReceiveCallback
is called again and again, always with 0 bytes to read. 现在发生的情况是,在客户端上关闭连接后,将一次又一次调用
DataReceiveCallback
,始终以0字节读取。
What I want to do is close the connection on the server if the client closes the connection. 我想做的是,如果客户端关闭连接,则关闭服务器上的连接。 What can I do to achieve this?
我该怎么做?
Note : I know that this example lacks proper error handling and you shouldn't start reading synchronously once you read something until the stream.Read()
returns 0. However, this suits my needs for now as I directly control all the data being sendt. 注意 :我知道此示例缺少适当的错误处理,并且一旦读取某些内容,就不应该开始同步读取,直到
stream.Read()
返回0。但是,由于我直接控制着所有要发送的数据,因此这适合我的需求。 。
You are calling BeginRead in a loop. 您正在循环调用BeginRead。 If the stream is done the read completes immediately with 0 bytes and the loop continues.
如果流完成,则读取立即以0字节完成,并且循环继续。
Your use of async IO makes no sense because you are blocking a thread waiting for the IO to complete. 使用异步IO毫无意义,因为您正在阻塞等待IO完成的线程。 Undoubtedly, you have copied that from bad MSDN samples (without understanding what this does, really).
毫无疑问,您是从不良的MSDN样本中复制的(实际上是在不了解其作用的情况下)。
Throw that away and use a normal loop for reading synchronously. 扔掉它并使用普通循环进行同步读取。 When the read call returns 0 you break the loop.
当读取调用返回0时,您将中断循环。
Also note, that TCP does not support messages in any way which you seem to assume right now. 还要注意,TCP似乎不以您现在认为的任何方式支持消息。 Delete all usages of
CanRead
and DataAvailable
. 删除
CanRead
和DataAvailable
所有用法。 As long as you are thinking in terms of these properties you are most likely doing it wrong. 只要您考虑这些属性,就很可能做错了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.