TcpClient vs Socket when dealing with asynchronousy

27,789

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.

Share:
27,789

Related videos on Youtube

darkey
Author by

darkey

Updated on June 11, 2020

Comments

  • darkey
    darkey almost 4 years

    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.

  • Şafak Gür
    Şafak Gür over 11 years
    I loved the Stepgen Toub's solution but I'd think you would be the one to write something like that. :)
  • svick
    svick over 11 years
    Similar situation with naming is with WebClient, where the *Async names are used for EAP (Event-based Asynchronous Pattern) methods. The way they solved it is to name the TAP methods *TaskAsync.
  • Stephen Cleary
    Stephen Cleary over 11 years
    @d4wn: Working on it. :) Due to my day job crazy-business, it probably won't be done till 2013. :(
  • Stephen Cleary
    Stephen Cleary over 11 years
    @svick: The naming situation in Socket is trickier. With this one class out of the entire BCL, they decided to use *Async to mean "using SocketAsyncEventArgs" instead of EAP. So, you can use *TaskAsync for the APM-style wrappers, and then if you follow both existing TAP and Socket conventions, you end up with *AsyncAsync for the SocketAsyncEventArgs-style wrappers. Ugly and certainly confusing methods for an already overburdened type.
  • darkey
    darkey over 11 years
    Once again ... Thanks Stephen ! ;)