繁体   English   中英

客户端关闭连接时在服务器上多次调用NetworkStream回调

[英]NetworkStream callback called multiple times on server when client closes connection

我正在编写一个模拟器来测试对象的反序列化,并通过TCP发送它们。 我在C#中使用TcpClient,TcpListener和NetworkStreams进行通信。 我想打开一个连接,发送多条消息,一段时间后关闭连接。 建立连接并双向发送数据包效果很好。 但是,当我关闭客户端的连接(调用stream.Close()tcpClient.Close() )时,一次又一次调用BeginRead的服务器回调。

客户端代码:

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();
}

服务器代码:

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();
}

当我在客户端上调用StopClient()时,正在调用服务器上的回调( DataReceiveCallback )。 stream.CanRead返回true,但是有0个字节要读取。 同样stream.DataAvailable为false。

但是,除此之外,我看不到在服务器端知道客户端关闭了连接。 当连接仍然打开时,可以从客户端接收0字节。

现在发生的情况是,在客户端上关闭连接后,将一次又一次调用DataReceiveCallback ,始终以0字节读取。

我想做的是,如果客户端关闭连接,则关闭服务器上的连接。 我该怎么做?

注意 :我知道此示例缺少适当的错误处理,并且一旦读取某些内容,就不应该开始同步读取,直到stream.Read()返回0。但是,由于我直接控制着所有要发送的数据,因此这适合我的需求。 。

您正在循环调用BeginRead。 如果流完成,则读取立即以0字节完成,并且循环继续。

使用异步IO毫无意义,因为您正在阻塞等待IO完成的线程。 毫无疑问,您是从不良的MSDN样本中复制的(实际上是在不了解其作用的情况下)。

扔掉它并使用普通循环进行同步读取。 当读取调用返回0时,您将中断循环。

还要注意,TCP似乎不以您现在认为的任何方式支持消息。 删除CanReadDataAvailable所有用法。 只要您考虑这些属性,就很可能做错了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM