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

问题描述 投票:2回答:1

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

为了从非阻塞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个字节,而非阻塞套接字没有数据丢失?

c++ sockets winsock send recv
1个回答
5
投票

如果使用非阻塞模式,则读取已到达系统的所有数据。一旦你读出所有数据recv返回错误,原因取决于系统:

  • EWOULDBLOCK(在posix系统中)
  • Windows套接字系统中的WSAEWOULDBLOCK

收到此错误后,您需要等待其他数据的到达。您可以通过以下几种方式实现:

  • 等待select / poll / epoll等特殊功能
  • 睡一段时间再试一次recv(用户空间轮询)

如果你需要减少延迟,最好选择/ poll / epoll。睡眠实现起来要简单得多。

此外,您需要考虑TCP是流协议,并不保持框架。这意味着您可以发送例如256个字节,然后发送另外256个字节,但一次接收512个字节。这也是相反的:您可以一次发送512个字节,第一次读取时接收256个字节,下次读取时接收另外256个字节。

© www.soinside.com 2019 - 2024. All rights reserved.