C 非阻止等待所有RECV数据

C++ nonblocking wait for all recv data

本文关键字:RECV 数据 等待      更新时间:2023-10-16

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

为了从非块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返回错误,原因是根据系统的不同:

  • ewoldblock(在Posix系统中)
  • Windows插座系统中的WSAEWOULDBLOCK

收到此错误后,您需要等待另一个数据的到达。您可以通过几种方式进行:

  • 等待特殊功能,例如Select/poll/epoll
  • 睡一段时间,尝试再次收到(用户空间轮询)

如果您需要减少延迟/poll/epoll是可取的。睡眠更容易实现。

您还需要考虑TCP是流协议,并且不会保持构架。这意味着您可以发送256个字节,然后再发送256个字节,但一次接收512个字节。这也相反:您可以一次发送512个字节,并在下一篇读取中收到256个字节,另外256个字节。