C# TcpClient的异步等待使用

C# TcpClient的异步等待使用,c#,asynchronous,tcp,C#,Asynchronous,Tcp,我最近开始使用新的C#5.0“异步”和“等待”关键字。我原以为我有点不对劲,但意识到有一件事让我怀疑。下面是我如何从远程TcpClient异步接收数据的。接受连接后,我调用此函数: static async void ReadAsync(TcpClient client) { NetworkStream ns = client.GetStream(); MemoryStream ms = new MemoryStream(); byte[] buffer = new by

我最近开始使用新的C#5.0“异步”和“等待”关键字。我原以为我有点不对劲,但意识到有一件事让我怀疑。下面是我如何从远程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);
        }
    }
}

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

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

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

因此,将
TcpClient.Connected
作为while循环条件不是一个好选择

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

将代码更新为:

静态异步void ReadAsync(TcpClient客户端)
{
NetworkStream ns=client.GetStream();
MemoryStream ms=新的MemoryStream();
字节[]缓冲区=新字节[1024];
while(true){
int bytesRead=wait ns.ReadAsync(buffer,0,buffer.Length);

如果(bytesRead我最终使用了长度前缀消息,每个数据包的前缀为4个字节,表示数据的长度。

所以你已经将数据写入
内存流
,你在同一
内存流
上一遍又一遍地调用
HandleMessage
,直到有更多数据可用。你期望发生什么?为什么要在此处检查
DataAvailable
?这与消息等无关。这主要用于决定是读取sync还是异步。您也不会清除后台缓冲区-您可以倒带,但您不会清除。我觉得我最近经常发布此消息,但只对事件处理程序使用
async void
s、 不返回任何内容的异步方法应该是
Async Task
。原因有很多,其中最重要的可能是未处理的异常会导致非常糟糕的意外行为。@Marc您确定
DataAvailable
?根据MSDN:
使用DataAvailable属性确定数据是否可用已准备好读取。如果DataAvailable为true,则立即返回读取调用。
@Yuval否,我说过调用方可以使用它来决定是读取同步还是异步。如果它不为零,我们可以合理地使用同步读取,并期望得到提示返回。如果它为零,我们应该切换到异步。它的其他用途不多,大多数情况下我都是当人们触摸可用的数据时,他们不适当地使用它(试图检测消息/帧的结尾-这不是它的意思)
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);
    }
}