导致Socket.Receive返回的最小字节数是多少?

我们正在使用一个应用程序协议,它指定前4个字节中消息的长度指示符。 Socket.Receive将返回与协议栈中当前或块一样多的数据,直到数据可用。 这就是为什么我们必须不断地从套接字读取,直到我们收到长度指示器中的字节数。 如果另一方关闭连接,Socket.Receive将返回0。 我明白了这一切。

是否有必须读取的最小字节数? 我问的原因是文档似乎完全有可能当socket.Receive可以返回时,整个长度指示符(4个字节)可能不可用。 然后我们必须继续努力。 最小化我们调用socket.receive的次数会更有效,因为它必须将内容复制到缓冲区中。 因此,获取长度指示符一次获得一个字节更安全,假设4个字节始终可用或我们是否应该继续尝试使用偏移量变量获得4个字节是否安全?

我认为可能存在某种默认最低级别的原因是我遇到了一个名为ReceiveLowWater变量的变量,我可以在套接字选项中设置它。 但这似乎只适用于BSD。 MSDN请参阅SO_RCVLOWAT。

它并不是那么重要,但我正在尝试编写unit testing。 我已经在界面后面包装了一个标准的.Net Socket。

假设4个字节始终可用是安全的

没有。 决不。 如果有人用telnet和键盘测试你的协议怎么办? 或者通过真正缓慢或繁忙的连接? 您可以一次接收一个字节, 也可以通过多个Receive()调用分割“长度指示符”。 这不是unit testing问题,它是导致生产问题的基本sockets问题,尤其是在压力情况下。

或者我们应该继续尝试使用偏移变量获取4个字节?

是的你应该。 为方便起见,您可以使用Socket.Receive()重载,它允许您指定要读取的字节数,这样您就不会读太多。 但是请注意它可以返回少于所需的值,这是offset参数的用途,因此它可以继续写入相同的缓冲区:

 byte[] lenBuf = new byte[4]; int offset = 0; while (offset < lenBuf.Length) { int received = socket.Receive(lenBuf, offset, lenBuf.Length - offset, 0); offset += received; if (received == 0) { // connection gracefully closed, do your thing to handle that } } // Here you're ready to parse lenBuf 

我认为可能存在某种默认最低级别的原因是我遇到了一个名为ReceiveLowWater变量的变量,我可以在套接字选项中设置它。 但这似乎只适用于BSD。

这是正确的,“接收低水位”标志仅用于向后兼容,并且除了抛出错误之外什么都不做,根据MSDN ,搜索SO_RCVLOWAT

Windows TCP / IP提供程序不支持此选项。 如果在Windows Vista及更高版本上使用此选项,则getsockopt和setsockopt函数将失败并显示WSAEINVAL。 在早期版本的Windows上,这些函数失败了WSAENOPROTOOPT“。所以我猜你必须使用偏移量。

这是一种耻辱,因为它可以提高性能。 但是,正如@cdleonard在评论中指出的那样,保持偏移变量的性能损失将是最小的,因为你通常会一次接收四个字节。

不,没有最小缓冲区大小,接收中的长度只需要与实际空间匹配。

如果在消息实际数据之前发送四个字节的长度,则接收方需要处理返回1,2,3或4个字节的情况并继续重复读取,直到收到所有四个字节,然后重复该过程以接收实际数据。