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

标签 c# .net sockets

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

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

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

它并不是那么重要,但我正在尝试编写单元测试。我已经在接口(interface)后面包装了一个标准的 .Net Socket。

最佳答案

is it safe to assume that 4 bytes will always be available

没有。绝不。如果有人正在使用 telnet 和键盘测试您的协议(protocol)怎么办?还是通过真正缓慢或繁忙的连接?您可以一次接收一个字节或通过多个Receive() 调用接收一个拆分的“长度指示器”。这不是单元测试问题,而是导致生产出现问题的基本套接字问题,尤其是在压力大的情况下。

or should we keep trying to get 4 bytes using an offset variable?

是的,你应该。为了您的方便,您可以使用 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

The reason that I think that there may be some sort of default minimum level is that I came across a varaible called ReceiveLowWater variable that I can set in the socket options. But this appears to only apply to BSD.

没错,根据 MSDN,包含“接收低水位”标志只是为了向后兼容,除了抛出错误外什么都不做。 , 搜索 SO_RCVLOWAT:

This option is not supported by the Windows TCP/IP provider. If this option is used on Windows Vista and later, the getsockopt and setsockopt functions fail with WSAEINVAL. On earlier versions of Windows, these functions fail with WSAENOPROTOOPT". So I guess you'll have to use the offset.

真可惜,因为它可以提高性能。然而,正如@cdleonard 在评论中指出的那样,保留偏移量变量对性能的影响很小,因为您通常一次接收四个字节。

关于c# - 导致 Socket.Receive 返回的最小字节数是多少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13087268/

相关文章:

c# - 如何在 DataGridView 中仅调整特定列的大小?

c# - 我如何在 LINQ 中写这个?

java - 如何将java小程序绑定(bind)到socket?

c# - 如何仅在程序集更改时使用 MSBuild 更新版本信息?

c# - 尝试 ajax 发布选定复选框列表时超出最大调用堆栈大小

c# - 如何在没有 NuGet 的情况下安装和设置 RESTSharp?

java - 如何在Java中仅通过套接字通信来实现流量控制?

c# - 如何获取局域网中打印机连接的计算机名和IP

c# - 如何模拟 IRepository<T>?

iphone - iOS 中的 BSD 套接字和超时