C# 处理异步时TcpClient与Socket
这不是另一个TcpClient vs套接字 TcpClient是围绕Socket类的包装器,用于简化开发,还公开了底层Socket 还是 在TcpClient类的MSDN库页面上,可以阅读以下备注: TcpClient类提供了连接、发送、, 以及以同步阻塞模式通过网络接收流数据 对于套接字类: Socket类允许您同时执行同步和 使用任何通信协议的异步数据传输 在ProtocolType枚举中列出 要仅通过TcpCient异步发送/接收某些数据,必须调用GetStream,以检索底层NetworkStream,通过调用其上的ReadAsync和WriteAsync方法,按照TAP模式(可能使用异步/等待构造),从底层NetworkStream异步读取/写入数据 要通过套接字异步发送/接收一些数据(我不是专家,但我认为我做对了),我们可以通过调用BeginRead/EndRead BeginWrite/EndWrite(或者只是ReadAsync或WriteAsync..不公开TAP模式-即不返回任务..来直接从套接字实例本身读/写数据 首先,你知道为什么.NET 4.5中的Socket类没有以任何方式实现TAP模式,即ReadAsync和WriteAsync返回任务(如果调用不同的事件以保持向后兼容性) 无论如何,从APM模型方法对构建任务方法非常简单,所以假设我将此异步方法(用于读取)称为ReadAsyncTAP(返回任务) 好吗?现在让我们假设我想编写一个客户端方法C# 处理异步时TcpClient与Socket,c#,sockets,asynchronous,tcpclient,async-await,C#,Sockets,Asynchronous,Tcpclient,Async Await,这不是另一个TcpClient vs套接字 TcpClient是围绕Socket类的包装器,用于简化开发,还公开了底层Socket 还是 在TcpClient类的MSDN库页面上,可以阅读以下备注: TcpClient类提供了连接、发送、, 以及以同步阻塞模式通过网络接收流数据 对于套接字类: Socket类允许您同时执行同步和 使用任何通信协议的异步数据传输 在ProtocolType枚举中列出 要仅通过TcpCient异步发送/接收某些数据,必须调用GetStream,以检索底层Networ
async Task ReadNbBytes(int nbBytes)
,我将从我的代码中调用它以从网络异步读取一定数量的字节
此方法完全基于TcpClient的实现将通过调用GetStream获得NetworkStream,并将包含一个异步循环,等待ReadAsync调用,直到缓冲区满为止
基于套接字的此方法的实现将包含一个异步循环,等待ReadAsyncTAP,直到缓冲区满为止
最后,从客户机代码的角度来看,我认为这没有什么区别。在这两种情况下,对wait ReadNbBytes
的调用将立即“返回”。然而,我想这在幕后会有所不同。。。
对于依赖NetworkStream的TcpClient,与直接使用socket相比,读取是否会在任何时候以某种方式阻塞?如果没有,在谈到同步阻塞模式时,是否对TcpClient的评论是错误的
如果有人能澄清,我们将不胜感激
谢谢。TcpClient流上的异步I/O不会阻塞。看起来MSDN文档是错误的(您可以在Reflector中通过遵循
NetworkStream
的异步I/O调用来验证这一点)
Stream
类型是“有趣的”:默认情况下,Stream
基类将通过在同步I/O上阻塞线程池线程来实现异步I/O。因此,您永远不希望在像MemoryStream
这样的东西上执行异步I/O,因为它只提供同步方法
NetworkStream
确实提供了异步I/O,因此NetworkStream
实例上的异步I/O实际上是异步的。但情况并非总是如此:FileStream
尤其如此
关于为什么Socket
没有TAP方法:这是一个非常好的问题!我认为这是一个疏忽,但现在.NET4.5发布了,看起来它是故意被遗漏的。这可能是因为他们不想使API过于复杂-套接字已经有了同步和两个异步API,涵盖了相同的操作集(Send
,SendTo
,ReceiveFrom
,Connect
,Accept
,Disconnect
)。TAP反过来需要两个额外的异步API来完成整个集合。这至少会引起一个有趣的命名情况(已经使用了*Async
名称,并且他们会为每个操作再添加两个*Async
名称)
旁注:“附加”API用于高性能异步Socket
通信。它们使用SocketAsyncEventArgs
,虽然使用起来不那么容易,但产生的内存垃圾更少。如果将TAP API添加到Socket
,则它们希望提供易于使用的版本(包装Begin
/End
)和更高性能的版本(包装Async
)
如果您对为
Socket
制作TAP方法感兴趣,那么Stephen Toub的方法是一个很好的起点(他只为高性能API提供包装器)。我在我的异步
支持的套接字中使用了类似的东西。我喜欢Stepgen Toub的解决方案,但我认为你会是编写类似内容的人。:)与命名类似的情况是WebClient
,其中*Async
名称用于EAP(基于事件的异步模式)方法。他们解决这个问题的方法是将TAP方法命名为*taskancy
@d4wn:Working on it.:)由于我的日常工作疯狂,这项工作可能要到2013年才能完成(@svick:SocketSocket
中的命名情况更为棘手。由于整个BCL中有一个类,他们决定使用*Async
来表示“使用SocketAsyncEventArgs
”因此,您可以对APM样式的包装使用*taskancy
,而不是EAP。如果您同时遵循现有的TAP和Socket
约定,那么SocketAsyncEventArgs
样式的包装将使用*asyncync
。对于已经过度使用的包装来说,这些方法既丑陋又令人困惑