首页 > 解决方案 > 如何实现此阻塞 Socket 方法的异步、基于 TcpClient/NetworkStream 的端口?

问题描述

我有这样的代码:

  public byte[] Read()
  {
     try
     {
        if (ClientSocket.Available != 0)
        {
           var InBuffer = new byte[ClientSocket.Available];
           ClientSocket.Receive(InBuffer);
           return InBuffer;
        }
        else
        {
           return null;
        }

     }
     catch (Exception ex)
     {
        Console.WriteLine(ex.ToString());
     }

  }

我想在async不完全改变代码流(疣和所有)的情况下做一个等价物,我遇到了问题,我也想切换到NetworkStream它内置的async方法

我希望 sig 是,Task<byte[]> Read()但是:

  1. NetworkStream.ReadAsync期望通过 abyte[]但不返回它,所以我不能简单地return stream.Read(...)
  2. NetworkStream似乎没有告诉您有多少字节可供读取。
  3. 如果没有可用的数据,我不想调用stream.Read只是传回 null。

因此,无论上述方法中的问题如何——我知道这不是最优的——我该怎么做呢?

目标是我能做的,或同等的。

byte [] bytes = await x.Read();

标签: c#task-parallel-library

解决方案


NetworkStream.ReadAsync 就像我遇到的大多数“给我一个字节缓冲区”方法一样;你给它一个字节数组并要求它从网络中读取 X 个字节并将其放入缓冲区。它可能比您要求的阅读量少,但不会阅读更多。它返回读取的字节数。您的代码始终保留字节数组缓冲区,因此您最终会执行以下操作:

byte[] buf = new byte[4096];
int bytesRead = await networkStream.ReadAsync(buf, 0, buf.Length. someCancelationToken);

byte[] rtn = new byte[bytesRead];
Array.Copy(buf, 0, rtn, 0, rtn.Length);

return rtn;

也就是说,您读取为异步操作,然后返回一个大小与报告为读取的字节数完全相同的数组,该数组来自缓冲区。使用此代码的方法将返回一个任务

NetworkStream 也有一个方法 CanRead 似乎可以解决您的“如果没有可阅读的内容”要求

还有一个 ReadAsync 的重载,它从您那里接受一个 Memory 作为缓冲区。你会以类似的方式使用它,除了当你知道已经读取了多少字节时你会调用它的 Slice 方法,以返回一个只查看缓冲区的那部分的内存。如果您随后在 Slice 调用的结果上调用 ToArray,您将获得一个大小符合您喜好的数组(读取字节数)。在这种情况下,两者可能几乎没有区别,尽管使用 Memory(及其相关的类 Span)可以减少某些操作的内存分配数量


推荐阅读