代码之家  ›  专栏  ›  技术社区  ›  darkey

处理异步时的TcpClient与Socket

  •  27
  • darkey  · 技术社区  · 13 年前

    这还不是另一个TcpClient与Socket的对比。

    TcpClient是Socket类周围的一个包装器,用于简化开发,同时还公开了底层的Socket。

    在TcpClient类的MSDN库页面上,可以阅读以下注释:

    TcpClient类提供了简单的方法来连接、发送、发送和发送数据, 以及在同步阻塞模式下通过网络接收流数据。

    对于Socket类:

    Socket类允许您执行同步和 使用任何通信协议的异步数据传输 列在ProtocolType枚举中。

    要仅通过TcpClient异步发送/接收某些数据,必须调用GetStream,以按照TAP模式(可能使用异步/等待构造),通过调用其上的ReadAsync和WriteAsync方法,从/上检索可以异步读取/写入数据的底层NetworkStream。

    要通过套接字异步发送/接收一些数据(我不是专家,但我认为我做得对),我们可以通过调用BeginRead/EndRead-BeginWrite/EndWrite(或者只是ReadAsync或WriteAsync..不暴露TAP模式,即不返回任务..混淆),直接从套接字实例本身读/写。

    首先,你知道为什么.NET 4.5中的Socket类没有以任何方式实现TAP模式,即ReadAsync和WriteAsync返回Task(如果以不同的方式调用事件以保留向后兼容性)吗?

    无论如何,从APM模型方法对构建Task方法已经足够简单了,所以假设我将这个异步方法(用于读取)称为ReadAsyncTAP(返回Task)。

    好啊现在我们假设我想编写一个客户端方法 async Task<Byte[]> ReadNbBytes(int nbBytes) 我将从我的代码中调用,以从网络异步读取一定数量的字节。

    完全基于TcpClient的此方法的实现将通过调用GetStream来获得NetworkStream,并将包含一个异步循环,等待ReadAsync调用,直到缓冲区满为止。

    基于Socket的此方法的实现将包含一个异步循环,等待ReadAsyncTAP,直到缓冲区满为止。

    最后,从客户端代码的角度来看,我认为这没有什么不同。在这两种情况下,对 await ReadNbBytes 将立即“返回”。然而,我想这在幕后会有所不同。。。 对于依赖NetworkStream的TcpClient,与直接使用套接字相比,读取是否在任何时候都会受阻?如果不是,在谈到同步阻塞模式时,对TcpClient的评论是错误的吗?

    如果有人能澄清,我将不胜感激!

    谢谢

    1 回复  |  直到 13 年前
        1
  •  28
  •   Dog Ears    11 年前

    异步I/O打开 TcpClient 流不会阻塞。MSDN文档似乎是错误的(您可以在Reflector中按照 NetworkStream 的异步I/O调用)。

    Stream 类型是“有趣的”:默认情况下 流动 基类将通过阻塞同步I/O上的线程池线程来实现异步I/O。因此,您永远不想在类似 MemoryStream ,仅提供同步方法。

    网络流 提供异步I/O,因此上的异步I/O 网络流 实例实际上是异步的。但情况并非总是如此: FileStream 特别是 usually not asynchronous but it is if you construct the instance just right

    关于原因 Socket 没有TAP方法:这是一个很好的问题!我以为这是一个疏忽,但现在.NET 4.5发布了,看起来它是故意遗漏的。可能他们只是不想让API过于复杂,Socket已经有了同步和 覆盖相同操作集的异步API( Send , SendTo , Receive , ReceiveFrom , Connect , Accept , Disconnect )。TAP反过来需要两个额外的异步API来实现该完整集合。这至少会引起一个有趣的命名情况( *Async 名字已经被取了,他们还会再加两个 *异步 每个操作的名称)。

    附带说明:“附加”API用于高性能异步 插座 表达他们使用 SocketAsyncEventArgs ,使用起来不那么容易,但产生的内存垃圾更少。如果TAP API被添加到 插座 ,他们希望提供两种易于使用的版本(包装 Begin / End )以及更高性能的版本(包装 Async )。

    如果你对制作的TAP方法感兴趣 插座 ,一个很好的起点是Stephen Toub的 Awaiting Socket Operations (他只为高性能API提供包装器)。我用类似的东西 async -已启用的套接字。

    推荐文章