C++ 非阻塞套接字 - 等待所有接收数据

标签 c++ sockets winsock send recv

我在我的本地系统上并没有遇到这个问题(当然),但是现在我正在设置一个虚拟服务器,我的部分代码遇到了一些问题。

为了从非阻塞 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/

相关文章:

javascript - Socket.io 设置导致数百个传输轮询 GET 请求

javascript - Socket.io 在第二个窗口上重复发出

c++ - Windows套接字编程中主机名的IP地址

c++ - 使用关键字在c++中解析文件

C++ 前向引用

c++ - Big Oh 是唯一用于衡量 STL 复杂性的符号吗

c - 使用C、winsock(windows)在三星Tizen推送服务器中推送消息

c++ - 下标时是否必须使用 constexpr 数组?

Java:通过套接字发送后公钥不同

c++ - 网络和消息