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/SendAsync
和Receive/ReceiveAsync
中用于服务器和客户端之间传输的byte[]
是否完全等同于NetworkStream
,我们通过调用tcpClient.GetStream()
得到对于 reading/writing、TcpListener
和 TcpClient
?
我不确定,但我认为它们是因为客户端和服务器的 SocketType
设置为 Stream
并且 send/receive
之间不应该有任何数据丢失那些 Streaming
协议!
区别在于 API 设计之一。
.NET Socket
class 是面向 Win32's Winsock, which itself is derived from BSD Sockets 的 OOP API。
Socket
API 是围绕其自己的发送和接收数据函数构建的,具有 send
、recv
等函数。在许多平台上,您可以使用 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 而不要使用 NetworkStream
或 TcpClient
.
- 如果您确实需要使用
Stream
模型传递网络数据,请使用 TcpClient
和 NetworkStream
- 但请注意 NetworkStream
的行为方式和您应该始终使用非阻塞(异步,又名 "overlapped IO")以避免瓶颈和程序冻结。
如果客户端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/SendAsync
和Receive/ReceiveAsync
中用于服务器和客户端之间传输的byte[]
是否完全等同于NetworkStream
,我们通过调用tcpClient.GetStream()
得到对于 reading/writing、TcpListener
和 TcpClient
?
我不确定,但我认为它们是因为客户端和服务器的 SocketType
设置为 Stream
并且 send/receive
之间不应该有任何数据丢失那些 Streaming
协议!
区别在于 API 设计之一。
.NET Socket
class 是面向 Win32's Winsock, which itself is derived from BSD Sockets 的 OOP API。
Socket
API 是围绕其自己的发送和接收数据函数构建的,具有 send
、recv
等函数。在许多平台上,您可以使用 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 而不要使用NetworkStream
或TcpClient
. - 如果您确实需要使用
Stream
模型传递网络数据,请使用TcpClient
和NetworkStream
- 但请注意NetworkStream
的行为方式和您应该始终使用非阻塞(异步,又名 "overlapped IO")以避免瓶颈和程序冻结。