简体   繁体   English

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

[英]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 . 删除CanReadDataAvailable所有用法。 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.

相关问题 客户端连接断开时的NetworkStream.BeginRead - NetworkStream.BeginRead when client connection is broken 服务器在发送后立即关闭时从NetworkStream读取数据 - Reading data from NetworkStream when server closes immediately after sending SignalR 服务器在客户端连接时立即关闭连接 - SignalR server closes connection immediately when the client connects 检测到与不安全的服务器(NetworkStream)的SslStream(客户端)连接尝试? - Detect an SslStream (client) connection attempt to an insecure Server (NetworkStream)? 服务器关闭保持活动状态的HTTP连接时检测或避免客户端CommunicationException - detecting or avoiding client CommunicationException when server closes keep-alive http connection 尝试将数据写入客户端时,C#中的简单套接字服务器意外关闭连接 - Simple socket server in C# unexpectedly closes connection when trying to write data to client 套接字单个客户端/服务器连接,服务器可以发送多次,客户端只能发送一次 - Socket single client/server connection, server can send multiple times, client can only once 套接字客户端是否会关闭连接并且服务器不知道这一点? - Can it happen that a socket client closes connection and the server doesen't know this? .NET中的异步读取问题 - 似乎我的回调被多次调用,而不应该 - Issues with Asynchronous Reads in .NET - it seems that my callback is being called multiple times when it should not be gRPC C# 服务器端,等待客户端关闭连接? - gRPC C# server side, waiting until client closes connection?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM