If client Socket
is defined like this:
args = new SocketAsyncEventArgs();
args.AcceptSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
await args.AcceptSocket.ConnectAsync(host, port);
and server lets it get connected in this way:
server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server.Bind(new IPEndPoint(0, port));
server.Listen(0);
var arg = new SocketAsyncEventArgs();
arg.AcceptSocket = await server.AcceptAsync();
Are the byte[]
used in Send/SendAsync
and Receive/ReceiveAsync
for transmission between server and client exact equivalent to NetworkStream
, which we get by calling tcpClient.GetStream()
for reading/writing, of TcpListener
and TcpClient
?
I'm not sure BUT I think they are because SocketType
for both client and server is set to Stream
and there shouldn't be any data loss in send/receive
between those Streaming
protocols!
The difference is one of API design.
The .NET Socket
class is an OOP API for Win32's Winsock, which itself is derived from BSD Sockets.
The Socket
API is built around its own functions for sending and receiving data, with functions like send
, recv
. On many platforms you can use the OS-provided filesystem API for reading and writing to sockets the same way you can read and write to local files.
In .NET, the Stream
class exists as an abstraction of any source or sink for binary data which can be read in a blocking or non-blocking (async
) manner regardless of where it came from (a file on a local disk, a file on a network share, a buffer in-memory, a TCP connection, a UDP connection, and so on). Read more about Stream
and its use as an abstraction here: https://learn.microsoft.com/en-us/dotnet/standard/io/
The point is that if you write a program or library that processes data - then rather than having to repeat your code over-and-over for different types of IO (files, in-memory buffers, TCP connections, etc) you only need to write your code once using Stream
and then magically your code can be used in many new places without much work.
But this comes with a downside of leaky-abstractions. We've since learned over the past 20-30 years of software-engineering that a single interface will not be perfect in every role - for example, a MemoryStream
is always non-blocking and doesn't need flushing - but a NetworkStream
(a Stream
API for Socket
) behaves very differently despite sharing the same API (remember: interfaces do not describe behavior!), such as how it buffers data internally (e.g. Nagle's algorithm). This is why .NET is now moving away from Stream
and towards the new Pipeline
API model.
So, in short:
Socket
internally.TcpClient
object adapts the Socket
API to the Stream
API (as NetworkStream
).
TcpClient
cannot exist without a Socket
.NetworkStream
is simply an adapter for Socket
for the Stream
API.Stream
API then you should only use the Socket
API and not use NetworkStream
or TcpClient
.Stream
model, then use TcpClient
and NetworkStream
- but be-aware of how NetworkStream
behaves and you should always use non-blocking (async, aka "overlapped IO") to avoid bottlenecks and program freezes.