C# 处理异步时的 TcpClient 与 Socket
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11981106/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
TcpClient vs Socket when dealing with asynchronousy
提问by darkey
This is not yet another TcpClient vs Socket.
这不是另一个 TcpClient 与 Socket。
TcpClient is a wrapper arround the Socket class to ease development, also exposing the underlying Socket.
TcpClient 是一个围绕 Socket 类的包装器,以简化开发,同时也暴露了底层的 Socket。
still ...
仍然 ...
On the MSDN library page for TcpClient class, one can read the following remark :
在 TcpClient 类的 MSDN 库页面上,可以阅读以下评论:
The TcpClient class provides simple methods for connecting, sending, and receiving stream data over a network in synchronous blocking mode.
TcpClient 类提供了在同步阻塞模式下通过网络连接、发送和接收流数据的简单方法。
And for the Socket class :
对于 Socket 类:
The Socket class allows you to perform both synchronous and asynchronous data transfer using any of the communication protocols listed in the ProtocolType enumeration.
Socket 类允许您使用 ProtocolType 枚举中列出的任何通信协议来执行同步和异步数据传输。
To send/receive some data asynchronously via the TcpCient only, a call to GetStream has to be made, to retrieve the underlying NetworkStream from/on which data can be read/write asynchronously by calling ReadAsync and WriteAsync methods on it, following the TAP pattern (potentially using async/await constructs).
要仅通过 TcpCient 异步发送/接收某些数据,必须调用 GetStream,按照 TAP 模式,通过调用 ReadAsync 和 WriteAsync 方法来检索可以异步读/写数据的底层 NetworkStream (可能使用 async/await 结构)。
To send/receive some data asynchronously via the Socket (I am not expert but I think I got it right), we can directly read/write from/on the socket instance itself by calling BeginRead/EndRead BeginWrite/EndWrite (or just ReadAsync or WriteAsync .. not exposing the TAP pattern - i.e. not returning a Task .. confusing).
要通过 Socket 异步发送/接收一些数据(我不是专家,但我认为我做对了),我们可以通过调用 BeginRead/EndRead BeginWrite/EndWrite(或者只是 ReadAsync 或WriteAsync .. 不公开 TAP 模式 - 即不返回 Task .. 令人困惑)。
First of all, any idea why the Socket class in .NET 4.5 does not implement in any way the TAP pattern, i.e ReadAsync and WriteAsync returning Task (event if called differently to preserve backward compat) ?
首先,知道为什么 .NET 4.5 中的 Socket 类没有以任何方式实现 TAP 模式,即 ReadAsync 和 WriteAsync 返回任务(如果调用不同的事件以保持向后兼容)?
Anyway, easy enough to build a Task method from APM model method pair, so let's say I call this asynchronous method (for read) ReadAsyncTAP (returning a Task).
无论如何,很容易从 APM 模型方法对构建一个 Task 方法,所以假设我调用这个异步方法(用于读取)ReadAsyncTAP(返回一个任务)。
Ok ? So now let's say I want to code a client method async Task<Byte[]> ReadNbBytes(int nbBytes)that I will call from my code to asynchronously Read a certain number of bytes from the Network.
好 ?所以现在假设我想编写一个客户端方法async Task<Byte[]> ReadNbBytes(int nbBytes),我将从我的代码中调用该方法以异步从网络读取一定数量的字节。
The implementation of this method based exclusively on a TcpClient would get the NetworkStream by calling GetStream and will contain an asynchronous loop awaiting on ReadAsync call(s) until buffer full.
此方法的实现完全基于 TcpClient 将通过调用 GetStream 获取 NetworkStream,并将包含一个异步循环,等待 ReadAsync 调用,直到缓冲区已满。
The implementation of this method based on the Socket would contain an asynchronous loop awaiting on ReadAsyncTAP until buffer full.
基于 Socket 的此方法的实现将包含一个异步循环,等待 ReadAsyncTAP 直到缓冲区已满。
At the end of the day, from the client code point of view, I suppose it makes no difference. In both case, the call to await ReadNbByteswill 'return' immediately. However, I suppose it makes a difference behind the scenes ...
For the TcpClient, relying on NetworkStream, does the reading somehow block or not at any point, compared to direct use of socket ? If not is the remark made for the TcpClient is wrong when talking about synchronous blocking mode ?
归根结底,从客户端代码的角度来看,我认为这没有区别。在这两种情况下,调用await ReadNbBytes都会立即“返回”。但是,我认为它在幕后有所不同......对于依赖于 NetworkStream 的 TcpClient,与直接使用 socket 相比,读取是否以某种方式阻塞或不阻塞?如果不是,那么在谈论同步阻塞模式时,为 TcpClient 所做的评论是错误的吗?
Would be greatly apprecited If anyone could clarify !
如果有人能澄清,将不胜感激!
Thanks.
谢谢。
采纳答案by Stephen Cleary
Asynchronous I/O on TcpClientstreams does not block. It looks like the MSDN docs are wrong (you can verify this in Reflector by following the NetworkStream's async I/O calls).
TcpClient流上的异步 I/O不会阻塞。看起来 MSDN 文档是错误的(您可以通过遵循NetworkStream的异步 I/O 调用在 Reflector 中验证这一点)。
Streamtypes are "interesting": by default, the Streambase class will implement asynchronous I/O by blocking a thread pool thread on synchronous I/O. So you don't ever want to do asynchronous I/O on something like a MemoryStream, which only provides synchronous methods.
Stream类型是“有趣的”:默认情况下,Stream基类将通过在同步 I/O 上阻塞线程池线程来实现异步 I/O。所以你永远不想在 a 之类的东西上做异步 I/O MemoryStream,它只提供同步方法。
NetworkStreamdoesprovide asynchronous I/O, so asynchronous I/O on NetworkStreaminstances is actually asynchronous. But this is not always the case: FileStreamin particular is usually notasynchronous but it is if you construct the instance just right.
NetworkStream确实提供了异步 I/O,所以NetworkStream实例上的异步 I/O实际上是异步的。但情况并非总是如此:FileStream特别是通常不是异步的,但如果您构造的实例恰到好处。
Regarding why Socketdoesn't have TAP methods: that is a very good question! I assumed it was an oversight, but now that .NET 4.5 is released, it looks like it was left out on purpose. It could be that they just don't want to overcomplicate the API - Socket already has synchronous and twoasynchronous APIs covering the same set of operations (Send, SendTo, Receive, ReceiveFrom, Connect, Accept, Disconnect). TAP would in turn require two additional asynchronous APIs for that full set. That would at least cause an interesting naming situation (the *Asyncnames are already taken, and they'd be adding two more *Asyncnames for each operation).
关于为什么Socket没有 TAP 方法:这是一个很好的问题!我认为这是一个疏忽,但现在 .NET 4.5 发布了,看起来它被故意遗漏了。可能是他们只是不想使 API 过于复杂 - Socket 已经有同步和两个异步 API,涵盖相同的操作集(Send, SendTo, Receive, ReceiveFrom, Connect, Accept, Disconnect)。反过来,TAP 将需要两个额外的异步 API 用于该完整集。这至少会导致一个有趣的命名情况(*Async名称已经被占用,并且他们*Async将为每个操作添加两个更多名称)。
Side note: the "additional" APIs are for high-performance asynchronous Socketcommunication. They use SocketAsyncEventArgs, which is not as easy to use but produces less memory garbage. If TAP APIs were added to Socket, they would want to provide both the easy-to-use versions (wrapping Begin/End) and the higher-performance versions (wrapping Async).
旁注:“附加” API 用于高性能异步Socket通信。他们使用SocketAsyncEventArgs,这不是那么容易使用,但产生的内存垃圾较少。如果将 TAP API 添加到 中Socket,他们将希望提供易于使用的版本 (wrapping Begin/ End) 和更高性能的版本 (wrapping Async)。
If you're interesting in making TAP methods for Socket, a good starting point is Stephen Toub's Awaiting Socket Operations(he only provides wrappers for the high-performance API). I use something similar for my async-enabled sockets.
如果您对为 制作 TAP 方法感兴趣Socket,一个很好的起点是 Stephen Toub 的Awaiting Socket Operations(他只为高性能 API 提供包装器)。我对async启用的套接字使用了类似的东西。

