For a given TCP connection, received data is buffered in the Kernel up to its buffer size limit (which is opaque to the application).
When an application wants to receive data it has to explicitly tell the Kernel how much data needs to be copied to the application buffer, because the buffer size is not infinite and that Kernel may be storing incoming payloads faster than your application could handle (don't forget your application is regularly preempted).
The only way for your application to receive data from a TCP socket is through recv()
, recvfrom()
, recvmsg()
system calls.
In your case, in User Space, all you can do is call the functions that correspond to those syscalls so you can receive data. Delivery is on-demand by design. In addition, the application won't know if data has arrived until it calls recv()
, recvfrom()
, recvmsg()
, select()
, poll()
or epoll()
.
Note: I am not a C# person. I know C and Kernel internals and that's pretty much it. I just wanted to point out the concept behind socket communcation.