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

C# 导致Socket.Receive返回的最小字节数是多少?,c#,.net,sockets,C#,.net,Sockets,我们使用的是一个应用程序协议,它在前4个字节中指定消息的长度指示符。在数据可用之前,Socket.Receive将返回协议堆栈中的数据。这就是为什么我们必须不断地从套接字读取数据,直到我们收到长度指示器中的字节数。如果另一端关闭了连接,Socket.Receive将返回0。我明白这一切 是否存在必须读取的最小字节数?我询问的原因是,从文档中可以看出,当socket.Receive返回时,整个长度指示符(4字节)可能不可用。我们必须继续努力。尽量减少调用socket.receive的次数会更有效,

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

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

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


这其实并不重要,但我正在尝试编写单元测试。我已经在接口后面包装了一个标准的.Net套接字。

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

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

假设4个字节总是可用,安全吗

不,从来没有。如果有人正在用telnet和键盘测试您的协议呢?还是通过真正的慢速或繁忙连接?您可以一次接收一个字节,也可以通过多个
receive()
调用拆分“长度指示器”。这不是单元测试的问题,而是导致生产中出现问题的基本套接字问题,特别是在紧张的情况下

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

是的,你应该。为了方便起见,您可以使用重载来指定要读取的字节数,这样就不会读取太多。但请注意,它返回的值可能小于所需值,这就是
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
byte[]lenBuf=新字节[4];
整数偏移=0;
while(偏移量
我认为可能存在某种默认最低级别的原因是我遇到了一个名为ReceiveLowWater的变量,我可以在套接字选项中设置它。但这似乎只适用于BSD

这是正确的,“接收低水位”标志仅用于向后兼容,除了抛出错误外,不起任何作用,如搜索
SO\u RCVLOWAT

Windows TCP/IP提供程序不支持此选项。如果在Windows Vista及更高版本上使用此选项,则getsockopt和setsockopt函数会因WSAEINVAL而失败。在早期版本的Windows上,这些函数会因wsaenoprotoop“”而失败,所以我想您必须使用偏移量


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

这不太可能,但您应该能够处理任意大小的读取。即使是1个字节。因为这不太可能his大多数时候都会发生,您应该不会受到任何性能影响。如果这4个字节不在流的最开始处,那么实际上很可能会在读取之间进行拆分。您的代码基本上就是我要查询的。从文档中可以看出,该重载返回的字节数可能少于您要求的4个字节。我使用上面的but在一个while循环中获取长度指示器中指定的所有数据。我知道这是正确的方法,因为我在文本和其他著名的SO用户中多次遇到过它。但是,当我们必须将该段代码放入while循环中获取正文时,为什么您建议相同的方法总是至少获取4个字节。@uriDium你说得对,我被另一个实现搞糊涂了,它一直保持
Receive()
ing直到读取
size
字节。正如文档中所述:“如果你使用的是面向连接的套接字,Receive方法将读取尽可能多的可用数据,直到size参数指定的字节数为止。“。所以,是的,你必须做偏移魔法。但据你所知,windows平台上的插座是否有某种最低水位类型的功能?BSD系统也有同样的方法?作为第三个参数传递给
Receive()
的值不应该随着
offset
的增长以同样的方式收缩吗?如果没有,则缓冲区的大小将达到,很可能会发生缓冲区溢出。@alk谢谢,你完全正确。我不应该从Notepad++编写代码,也不应该发布未经测试的代码,尽管这只是为了说明这个想法。:-)