请原谅我对任务和异步的知识不足。
使用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 client)显然是失败的,因为如果没有可用数据,ReadAsync将始终返回0字节。
我应该如何使用异步/任务来编写ReadClientAsync来防止出现繁忙循环的情况?我以前在这些情况下使用BeginRead / EndRead,效果很好。在这种特殊情况下,这将是解决方案吗?
谢谢,
不,这不是TCP的工作方式。
NetworkStream
当另一侧启动(可能是单向)关闭时,则被视为处于“流结束”状态。那是ReadAsync
(或Read
就此而言)返回零的时间-在任何其他情况下都不会。
MSDN文档很容易被误解-主要是因为您查找的文档不正确。NetworkStream
不会覆盖ReadAsync
(没有理由这样做),因此您实际上正在查看有关generic的文档Stream.ReadAsync
。相反,的文档NetworkStream.Read
说:
此方法将数据读入buffer参数,并返回成功读取的字节数。如果没有可用的数据读取,则Read方法将返回0。Read操作将读取尽可能多的数据,直到size参数指定的字节数为止。如果远程主机关闭连接,并且已收到所有可用数据,则Read方法立即完成并返回零字节。
请注意最后一句话,它告诉您NetworkStream
“结束播放”的实际含义。这就是关闭TCP连接的方式。
您对此的反应通常还应该从另一端关闭连接-使用return
辅助方法并清理套接字。无论如何,请勿重复while (true)
要再一次-您将得到一个无限循环,该循环占用100%的CPU。
如果您想获得有关如何使用C#异步套接字的一些指导await
,请参阅https://github.com/Luaancz/Networking/tree/master/Networking%20Part%202上的示例。请注意免责声明-绝不准备生产。但这确实解决了人们在实现TCP通信时常犯的一些错误。