dar*_*key 23 c# sockets asynchronous tcpclient async-await
这不是另一个TcpClient vs Socket.
TcpClient是Socket类的一个包装器,用于简化开发,同时也暴露了底层的Socket.
还是......
在TcpClient类的MSDN库页面上,可以阅读以下注释:
TcpClient类提供了在同步阻塞模式下通过网络连接,发送和接收流数据的简单方法.
而对于Socket类:
Socket类允许您使用ProtocolType枚举中列出的任何通信协议执行同步和异步数据传输.
要仅通过TcpCient异步发送/接收某些数据,必须调用GetStream,通过在TAP模式上调用ReadAsync和WriteAsync方法,从中检索基础NetworkStream,可以异步读/写数据. (可能使用async/await构造).
要通过Socket异步发送/接收一些数据(我不是专家,但我认为我做对了),我们可以通过调用BeginRead/EndRead BeginWrite/EndWrite(或者只是ReadAsync或者)来直接读取/写入套接字实例本身. WriteAsync ..不暴露TAP模式 - 即不返回任务..令人困惑).
首先,任何想法为什么.NET 4.5中的Socket类没有以任何方式实现TAP模式,即ReadAsync和WriteAsync返回Task(如果调用不同的事件以保留向后compat)?
无论如何,很容易从APM模型方法对构建一个Task方法,所以让我说我调用这个异步方法(用于读取)ReadAsyncTAP(返回一个Task).
好 ?所以现在让我说我想编写一个客户端方法async Task<Byte[]> ReadNbBytes(int nbBytes),我将从我的代码调用异步从网络读取一定数量的字节.
完全基于TcpClient的此方法的实现将通过调用GetStream来获取NetworkStream,并且将包含等待ReadAsync调用的异步循环,直到缓冲区满.
基于Socket的这种方法的实现将包含一个等待ReadAsyncTAP的异步循环,直到缓冲区满.
在一天结束时,从客户端代码的角度来看,我认为它没有任何区别.在这两种情况下,呼叫await ReadNbBytes将立即"返回".但是,我认为它在幕后产生了影响......对于TcpClient,依赖于NetworkStream,与直接使用套接字相比,读取是否会以某种方式阻塞或不阻止?如果没有,那么在谈论同步阻塞模式时,TcpClient的注释是错误的吗?
如果有人能澄清,将非常感激!
谢谢.
Ste*_*ary 26
TcpClient流上的异步I/O 不会阻塞.看起来MSDN文档是错误的(您可以通过跟踪NetworkStream异步I/O调用在Reflector中验证这一点).
Stream类型是"有趣的":默认情况下,Stream基类将通过阻塞同步I/O上的线程池线程来实现异步I/O. 所以你不想在类似a的东西上做异步I/O MemoryStream,它只提供同步方法.
NetworkStream 确实提供了异步I/O,因此NetworkStream实例上的异步I/O 实际上是异步的.但情况并非总是如此:FileStream特别是通常不是异步的,但如果你正确构造实例则是这样.
关于为什么Socket没有TAP方法:这是一个非常好的问题!我认为这是一个疏忽,但现在.NET 4.5已经发布,看起来它是故意遗漏的.这可能是因为他们只是不想过于复杂的API -插座已经有同步和2个异步API的覆盖相同的一组操作(Send,SendTo,Receive,ReceiveFrom,Connect,Accept,Disconnect).TAP反过来又要求为该全套设置两个额外的异步API.这至少会导致一个有趣的命名情况(*Async名称已经被采用,并且他们*Async将为每个操作添加两个名称).
附注:"附加"API用于高性能异步Socket通信.他们使用SocketAsyncEventArgs,这不是那么容易使用,但产生的内存垃圾更少.如果添加了TAP API Socket,他们希望提供易于使用的版本(包装Begin/ End)和更高性能的版本(包装Async).
如果你有兴趣制作TAP方法Socket,那么一个很好的起点是Stephen Toub的等待套接字操作(他只提供高性能API的包装器).我使用类似于我的async启用套接字的东西.