为什么套接字读取了可用字节数量不止0个字节?

9
我发现以下代码会导致CPU使用率达到100%的循环:
byte[] buffer = new byte[0x10000];
while (true) {
    if (socket.Poll (5000000, SelectMode.SelectRead) == false)
        continue;
    int available = socket.Available;
    if (available == 0)
        return;
    int read = socket.Receive (buffer);
    Console.WriteLine ("Read: " + read + " Available: " + available);
    /* ... */
}

输出结果如下:
Read: 0 Available: 1
Read: 0 Available: 1
Read: 0 Available: 1
Read: 0 Available: 1
Read: 0 Available: 1
...

我原本期望socket.Receive方法读取剩余的字节,但它显然没有这样做,导致我的代码一直循环在100%处。
正如jgauffin所建议的,文档中写道:
如果远程主机使用Shutdown方法关闭Socket连接,并且已经接收到所有可用数据,则Receive方法将立即完成并返回零字节。
因此,读取0有点意料之中,但只有在所有数据被读取后,socket.Available才会声明没有数据可用。 Socket.Available的文档仅提到关闭连接会引发异常。
我该如何确保读取最后一个字节?
相关:这个是一个关于如何检测关闭连接的答案,它依赖于当没有更多数据并且连接已关闭时,socket.Available为0。

我认为当连接关闭时,Available返回0是一个bug。微软的某个人可能会看到你的问题并给出一个合适的答案。你可以尝试发送一些数据并查看Send方法返回的字节数。如果它返回0,则表示连接确实已关闭。 - jgauffin
1个回答

12

你读过文档了吗?

“0字节已读”意味着远程端点已经断开连接。

要么使用阻塞套接字,要么使用异步方法如BeginReceive()。在.NET中不需要使用Poll


我发现文档的某些部分有点含糊不清,说明断开连接→读取0,并不一定是反过来。那么Available>0呢?我该如何解释它? - hultqvist
2
很久以前我读过这份文档,我同意它不是很清晰。您应该始终将从Receive()接收到的0视为断开连接的返回值,不管其他方法/属性说什么。引用自MSDN:如果您处于非阻塞模式,并且协议堆栈缓冲区中没有可用数据,则接收方法将立即完成并抛出 SocketException。我强烈建议您停止在.NET中使用非阻塞套接字。 - jgauffin
你可以在这里找到详细的解释:https://dev59.com/VHM_5IYBdhLWcg3waSb9#1388691 - 56ka
@zahirdhada:现在你可以了。 - jgauffin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接