如果客户端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[]
和Send/SendAsync
中用于服务器和客户端之间传输的Receive/ReceiveAsync
是否精确等于NetworkStream
,我们通过调用tcpClient.GetStream()
进行读写来获得TcpListener
和TcpClient
?
[我不确定这是因为客户端和服务器的SocketType
都设置为Stream
,并且在这些send/receive
协议之间的Streaming
中不应有任何数据丢失!
差异是API设计之一。
。NET Socket
类是Win32's Winsock的OOP API,它本身是从BSD Sockets派生的。
Socket
API围绕它自己的发送和接收数据的功能而构建,具有send
,recv
之类的功能。在许多平台上,您可以使用操作系统提供的文件系统API来读取和写入套接字,就像读取和写入本地文件一样。
在.NET中,Stream
类作为二进制数据的任何源或宿的抽象存在,可以以阻塞或非阻塞(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。从那以后,我们在过去20到30年的软件工程中获悉,单个接口在每个角色中都不是完美的-例如,MemoryStream
始终是非阻塞的,不需要刷新-但[尽管共享相同的API,但C0](NetworkStream
的Stream
API)的行为却大不相同(请记住:接口没有描述行为!),例如它如何在内部缓冲数据(例如Nagle的算法)。 Socket
。
因此,简而言之:
Stream
and towards the new Pipeline
API model。Stream
对象使Pipeline
API适应Socket
API(作为TcpClient
)。Socket
,就不会存在Stream
。>>NetworkStream
只是TcpClient
API的Socket
的NetworkStream
。Socket
API,而不要使用Stream
或Stream
。Socket
模型传递网络数据,请使用NetworkStream
和TcpClient
-但要注意Stream
的行为,因此应始终使用非阻塞(异步,也称为“ IO重叠”),以避免瓶颈和程序冻结。