0

如果客户端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();

byte[]用于服务器和客户端之间传输的 inSend/SendAsync和for是否Receive/ReceiveAsync完全等同于NetworkStream我们通过调用tcpClient.GetStream()读/写得到的TcpListenerTcpClient

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

4

1 回答 1

0

不同之处在于API设计之一。

.NETSocket类是Win32 的 Winsock的 OOP API ,它本身是从BSD Sockets派生的。

SocketAPI 是围绕其自己的用于发送和接收数据的函数构建的,具有诸如send、之类的函数recv。在许多平台上,您可以使用操作系统提供的文件系统 API 来读取和写入套接字,就像您可以读取和写入本地文件一样。

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

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

但这带来了泄漏抽象的缺点。在过去 20 到 30 年的软件工程中,我们已经了解到,单个接口不会在每个角色中都是完美的——例如,aMemoryStream始终是非阻塞的并且不需要刷新——但是) 尽管共享相同的 API,但行为非常不同(请记住:接口不描述行为!),例如它如何在内部缓冲数据(例如 Nagle 算法)。这就是 .NET 现在远离和转向新API 模型的原因。NetworkStreamStreamSocketStreamPipeline

所以,简而言之:

  • 网络连接始终Socket在内部使用。
  • TcpClient对象使SocketAPI适应StreamAPI(如NetworkStream)。
    • 所以TcpClient没有 a 就不能存在Socket
    • aNetworkStream只是API的适配器SocketStream
  • 如果您的程序不需要使用StreamAPI 抽象出 IO,那么您应该只使用SocketAPI 而不要使用NetworkStreamor TcpClient
  • 如果您确实需要使用Stream模型传递网络数据,请使用TcpClientand NetworkStream- 但要注意NetworkStream行为方式,并且您应该始终使用非阻塞(异步,也称为“重叠 IO”)以避免瓶颈和程序冻结。
于 2019-10-29T06:30:33.900 回答