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