我在我的本地系统上并没有遇到这个问题(当然),但是现在我正在设置一个虚拟服务器,我的部分代码遇到了一些问题。
为了从非阻塞 TCP recv() 接收所有数据,我有这个函数
ssize_t Server::recvAll(int sockfd, const void *buf, size_t len, int flags) {
// just showing here that they are non-blocking sockets
u_long iMode=1;
ioctlsocket(sockfd,FIONBIO,&iMode);
ssize_t result;
char *pbuf = (char *)buf;
while ( len > 0 ) {
result = recv(sockfd,pbuf,len,flags);
printf("\tRES: %d", result);
if ( result <= 0 ) break;
pbuf += result;
len -= result;
}
return result;
}
我注意到 recvAll
通常 打印 RES: 1024
(1024 是我发送的字节数)并且效果很好.但不太常见的是,数据丢失并且它仅打印 RES: 400
(其中 400 是大于 0 且小于 1024 的某个数字)并且我的代码不起作用,因为它需要所有 1024 个字节。
我也试过打印 WSAGetLastError()
并在调试中运行,但由于打印/调试,我没有遇到这个问题,看起来程序运行得足够慢。
我认为这个函数对阻塞套接字非常有效,但对非阻塞套接字无效。
关于我可以采取的测量的任何建议,以确保我在非阻塞套接字上确实接收到所有 1024 字节而没有数据丢失?
最佳答案
如果你使用非阻塞模式,那么你会读取所有已经到达系统的数据。读出所有数据后,recv 返回错误,原因取决于系统:
- EWOULDBLOCK(在 posix 系统中)
- Windows 套接字系统中的 WSAEWOULDBLOCK
一旦收到此错误,您需要等待另一个数据的到来。您可以通过多种方式做到这一点:
- 等待 select/poll/epoll 等特殊函数
- 休眠一段时间并尝试再次接收(用户空间轮询)
如果需要减少延迟,最好选择/poll/epoll。 sleep 实现起来要简单得多。
您还需要考虑 TCP 是流协议(protocol)并且不会保持帧。这意味着您可以发送 256 个字节,然后再发送 256 个字节,但一次接收 512 个字节。这也适用于相反的方式:您可以一次发送 512 个字节,并在第一次读取时接收 256 个字节,在下一次读取时接收另外 256 个字节。
关于C++ 非阻塞套接字 - 等待所有接收数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47975612/