TCP 包装器的 GetStream().Read/Write 和 Socket 的 Receive/Send 之间有什么区别吗

Is there any difference between TCP wrappers' GetStream().Read/Write and Socket's Receive/Send

如果客户端Socket定义如下:

args = new SocketAsyncEventArgs();
args.AcceptSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
await args.AcceptSocket.ConnectAsync(host, port);

服务器让它以这种方式连接:

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();

Send/SendAsyncReceive/ReceiveAsync中用于服务器和客户端之间传输的byte[]是否完全等同于NetworkStream,我们通过调用tcpClient.GetStream()得到对于 reading/writing、TcpListenerTcpClient?

我不确定,但我认为它们是因为客户端和服务器的 SocketType 设置为 Stream 并且 send/receive 之间不应该有任何数据丢失那些 Streaming 协议!

区别在于 API 设计之一。

.NET Socket class 是面向 Win32's Winsock, which itself is derived from BSD Sockets 的 OOP API。

Socket API 是围绕其自己的发送和接收数据函数构建的,具有 sendrecv 等函数。在许多平台上,您可以使用 OS 提供的文件系统 API 以与读取和写入本地文件相同的方式读取和写入套接字。

在 .NET 中,Stream class 作为二进制数据的任何源或接收器的抽象存在,可以以阻塞或非阻塞方式读取 (async)无论它来自何处(本地磁盘上的文件、网络共享上的文件、内存中的缓冲区、TCP 连接、UDP 连接等)。在此处阅读有关 Stream 及其抽象用法的更多信息:https://docs.microsoft.com/en-us/dotnet/standard/io/

重点是,如果您编写处理数据的程序或库,则不必为不同类型的 IO(文件、内存缓冲区、TCP 连接等)一遍又一遍地重复您的代码) 您只需要使用 Stream 编写一次代码,然后您的代码就可以神奇地用于许多新地方而无需太多工作。

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.

所以,简而言之:

  • 网络连接始终在内部使用Socket
  • TcpClient 对象将 Socket API 适配为 Stream API(如 NetworkStream)。
    • 所以 TcpClient 不能没有 Socket
    • NetworkStream 只是 an adapter 对于 Socket 对于 Stream API.
  • 如果您的程序不需要使用 Stream API 抽象化 IO 那么您应该只使用 Socket API 而不要使用 NetworkStreamTcpClient.
  • 如果您确实需要使用 Stream 模型传递网络数据,请使用 TcpClientNetworkStream - 但请注意 NetworkStream 的行为方式和您应该始终使用非阻塞(异步,又名 "overlapped IO")以避免瓶颈和程序冻结。