TcpClient; NetworkStream; ReadAsync; C#
本文关键字:ReadAsync NetworkStream TcpClient | 更新日期: 2023-09-27 18:29:30
请原谅我对任务和异步缺乏了解。
使用TcpClient类,我正在创建一个与可用服务器的连接:
void async RunClientAsync()
{
TcpClient client = new TcpClient();
try
{
await client.ConnectAsync(IPAddress.Parse("1.1.1.1"), 8889);
Task.Start(() => ReadClientAsync(client));
}
catch (Exception ex)
{
HandleException(ex);
}
}
// -----
void async ReadClientAsync(TcpClient client)
{
byte[] bf = new byte[2048];
try
{
while(true)
{
int br = await client.NetworkStream().ReadAsync();
if (br > 0)
{
HandleInboundData(bf, br);
}
}
}
catch (Exception ex)
{
HandleException(ex);
}
}
助手方法HandleException(Exception-ex)和HandleInboundData(byte[]buffer,int length)将执行假定的任务。
与服务器的连接将是永久的,从服务器接收的数据将具有未知的长度和频率,其想法是抛出一个只有在数据可用时才接收和处理入站数据的任务。
ReadClientAsync(TcpClient客户端)是一个明显的失败,因为如果没有可用的数据,ReadAsync将始终返回0字节。
我应该如何使用async/task编写ReadClientAsync来防止繁忙的循环情况?我以前在这些情况下使用过BeginRead/EndRead,效果很好。在这种特殊情况下,这会是解决方案吗?
谢谢你,
不,TCP不是这样工作的。
当另一侧启动(可能是单向)关闭时,NetworkStream
被认为处于"流结束"状态。这时ReadAsync
(或Read
)返回零——在任何其他情况下都不会。
MSDN文档很容易被误解,主要是因为您看错了文档。NetworkStream
不会覆盖ReadAsync
(没有理由这样做),所以您实际上正在查看通用Stream.ReadAsync
的文档。相比之下,NetworkStream.Read
的文档显示:
此方法将数据读取到缓冲区参数中,并返回成功读取的字节数。如果没有可供读取的数据,Read方法将返回0。Read操作读取尽可能多的可用数据,最多可读取size参数指定的字节数。如果远程主机关闭连接,并且已接收到所有可用数据,则Read方法将立即完成并返回零字节。
请注意最后一句,它告诉了NetworkStream
成为"流的结尾"的实际含义。TCP连接就是这样关闭的。
对此的响应通常也应该是关闭另一端的连接-从helper方法中取出return
并清理套接字。无论如何,不要再重复while (true)
——你只会得到一个消耗100%CPU的无限循环。
如果您想要一些关于如何使用await
处理C#异步套接字的指针,请查看我的示例https://github.com/Luaancz/Networking/tree/master/Networking%20Part%202.请注意免责声明-这绝不是生产准备好的。但它确实解决了人们在实现TCP通信时犯的一些非常常见的错误。