簡體   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