Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TcpClient vs Socket when dealing with asynchronousy

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.

like image 988
darkey Avatar asked Aug 16 '12 05:08

darkey


People also ask

Is TcpClient a Socket?

TcpClient creates a Socket to send and receive data over a network. Classes deriving from TcpClient can use this property to get or set this Socket . Use the underlying Socket returned from Client if you require access beyond that which TcpClient provides.

What is a TcpClient?

The TcpClient class provides simple methods for connecting, sending, and receiving stream data over a network in synchronous blocking mode. In order for TcpClient to connect and exchange data, a TcpListener or Socket created with the TCP ProtocolType must be listening for incoming connection requests.

Is TCP asynchronous?

You can read data asynchronously with the TCP/IP object in one of these two ways: Continuously, by setting ReadAsyncMode to continuous . In this mode, data is automatically stored in the input buffer as it becomes available from the server. Manually, by setting ReadAsyncMode to manual .


1 Answers

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.

like image 58
Stephen Cleary Avatar answered Sep 21 '22 13:09

Stephen Cleary