异步等待使用TcpClient

Phi*_*aré 5 c# asynchronous tcp

我最近开始使用新的C#5.0"async"和"await"关键字.我以为我得到了扭曲,但意识到有一件事让我怀疑.这是我从远程TcpClient异步接收数据的方式.一旦我接受连接,我就调用这个函数:

static async void ReadAsync(TcpClient client)
{
    NetworkStream ns = client.GetStream();
    MemoryStream ms = new MemoryStream();
    byte[] buffer = new byte[1024];

    while(client.Connected)
    {
        int bytesRead = await ns.ReadAsync(buffer, 0, buffer.Length);
        ms.Write(buffer, 0, bytesRead);
        if (!ns.DataAvailable)
        {
            HandleMessage(ms.ToArray());
            ms.Seek(0, SeekOrigin.Begin);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

收到数据后,循环就会继续运行而不会读取任何内容.我在循环中用Console.WriteLine测试了这个.我正确使用它吗?我觉得我不应该使用while循环...

com*_*lip 6

TcpClient.Connected值不会立即更新。根据 MSDN:

true如果客户端套接字在最近的操作中连接到远程资源;否则,false

所以有TcpClient.Connected一个 while 循环条件不是一个好的选择。

TcpClient.DataAvailable 用于同步操作,不用于异步操作。

将您的代码更新为:

static async void ReadAsync(TcpClient client)
{
    NetworkStream ns = client.GetStream();
    MemoryStream ms = new MemoryStream();
    byte[] buffer = new byte[1024];

    while(true) {
        int bytesRead = await ns.ReadAsync(buffer, 0, buffer.Length);
        if (bytesRead <= 0)
            break;
        ms.Write(buffer, 0, bytesRead);
        HandleMessage(ms.ToArray());
        ms.Seek(0, SeekOrigin.Begin);
    }
}
Run Code Online (Sandbox Code Playgroud)

ReadAsync返回 0 时,表示 TCP 连接关闭或关闭。在 MSDN 中:

TResult参数的值包含读入缓冲区的总字节数。如果当前可用的字节数小于请求的数量,则结果值可能小于请求的字节数,如果已到达流的末尾,则结果值可以为 0(零)。


Phi*_*aré 0

我最终使用了长度前缀消息,为每个数据包添加 4 个字节作为前缀,表示即将到来的数据的长度。