2016-01-08 105 views
2

请原谅我对任务和异步的认识不足。TcpClient;的NetworkStream; ReadAsync; C#

使用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(异常前)和HandleInboundData(字节[]缓冲液,INT长度)将执行假定任务。

与服务器的连接将是永久和从服务器接收到的数据将是未知的长度和频率的,其想法是抛出一个任务在那里,接收和处理,只有当数据是可用的入站数据。

ReadClientAsync(TcpClient客户端)明显失败,因为如果没有可用数据,ReadAsync将始终返回0字节。

我应该如何使用async/task编写ReadClientAsync以防止繁忙循环情况?在这些情况之前,我已经使用了BeginRead/EndRead,它工作正常。这是否是这种特殊情况下的解决方案?

谢谢,

+0

谢谢你的评论。这是来自ReadAsync的MSDN条目:“表示异步读取操作的任务。TResult参数的值包含读入缓冲区的总字节数。如果当前可用的字节数小于请求的数字,结果值可能会小于请求的字节数,如果已到达流的末尾,结果值可能为0(零)。“我理解了流的结束意味着流中没有数据要读取。 – Jam

+0

了解。谢谢Luaan。我相信我明白问题出在哪里。 – Jam

回答

4

不,这不是TCP的工作原理。

NetworkStream被认为是在另一方发起(可能的单向)关闭时处于“流结束”状态。那时ReadAsync(或Read,就此而言)返回零 - 不在其他情况下。

MSDN文档很容易被误解 - 主要是因为您正在查看错误的文档。 NetworkStream不会覆盖ReadAsync(没有理由这样做),所以您实际上正在查看通用Stream.ReadAsync的文档。相反,NetworkStream.Read的说明文件说:

该方法将数据读入缓冲区参数并返回成功读取的字节数。如果没有数据可用于读取,则Read方法返回0. Read操作读取尽可能多的数据,直到由size参数指定的字节数。如果远程主机关闭连接,并且已收到所有可用数据,则Read方法立即完成并返回零字节。

请注意最后一句,它告诉你它实际上对于NetworkStream是什么意思是“流结束”。这是TCP连接如何关闭的。

您对此的回应通常应该是关闭另一端的连接--以外的辅助方法并清理套接字。在任何情况下,不要再次重复while (true) - 你只会得到一个无限循环,它可以100%地处理你的CPU。

如果您想要了解如何处理带有await的C#异步套接字的几个指针,请查看我的示例https://github.com/Luaancz/Networking/tree/master/Networking%20Part%202。请注意免责声明 - 这绝不是生产准备就绪。但它确实解决了人们在实现TCP通信时犯的一些常见错误。

相关问题