This is not yet another TcpClient vs Socket.
TcpClient is a wrapper arround the Socket class to ease development, also exposing the underlying Socket.
still ...
On the MSDN library page for TcpClient class, one can read the following remark :
The TcpClient class provides simple methods for connecting, sending, and receiving stream data over a network in synchronous blocking mode.
And for the Socket class :
The Socket class allows you to perform both synchronous and asynchronous data transfer using any of the communication protocols listed in the ProtocolType enumeration.
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).
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).
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) ?
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).
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.
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.
The implementation of this method based on the Socket would contain an asynchronous loop awaiting on ReadAsyncTAP until buffer full.
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 ReadNbBytes
will '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 ?
Would be greatly apprecited If anyone could clarify !
Thanks.
Asynchronous I/O on TcpClient
streams 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).
Stream
types are "interesting": by default, the Stream
base 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.
NetworkStream
does provide asynchronous I/O, so asynchronous I/O on NetworkStream
instances is actually asynchronous. But this is not always the case: FileStream
in particular is usually not asynchronous but it is if you construct the instance just right.
Regarding why Socket
doesn'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 two asynchronous 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 *Async
names are already taken, and they'd be adding two more *Async
names for each operation).
Side note: the "additional" APIs are for high-performance asynchronous Socket
communication. 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
).
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.