TcpClient的;的NetworkStream; ReadAsync; C#

时间:2016-01-08 20:38:17

标签: c# tcpclient beginread

请原谅我对任务和异步的不了解。

使用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,它运行良好。在这种特殊情况下,这会是解决方案吗?

谢谢,

1 个答案:

答案 0 :(得分:4)

不,那不是TCP的工作方式。

NetworkStream被认为是在"流的末尾"当另一方启动(可能是单向)关闭时的状态。那个ReadAsync(或Read就此而言)返回零的情况 - 不是在任何其他情况下。

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

  

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

请注意最后一句,它告诉您NetworkStream对于"流的结束"实际意味着什么。这就是TCP连接的关闭方式。

您对此的响应通常应该是从另一方关闭连接 - return从您的帮助方法中清除套接字。在任何情况下,不要再重复while (true) - 你只是要获得一个无限循环来吃100%的CPU。

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