windows下udp的recvfrom函数设置超时没法退出?

windows下udp的recvfrom函数设置超时没法退出?

struct timeval tv_out;
tv_out.tv_sec = 0;//这里改为1s下面设置为0,可以正常退出,但是超时时间为1s感觉太长了
tv_out.tv_usec = RECVTIMEOUT;//这里时间设置多少都没生效,退出时还是卡在recvfrom函数
if(setsockopt(m_nRecvSockFd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv_out, sizeof(tv_out)) == -1)
{
    //qDebug(QString("设置超时 failed %1").arg(WSAGetLastError()));
#ifdef  _WIN32
    closesocket(pSocketFd);
#elif linux
    close(pSocketFd);
#elif unix // all unices not caught above
    close(pSocketFd);
#else
# error "Unknown"
#endif
    return false;
}

有朋友做过类似的项目吗?提供一点经验,之所以用阻塞的方式原因如下(优点:减少丢包):

阻塞模式
在阻塞模式下,程序调用recvfrom函数后会一直等待,直到有数据可读取。recvfrom函数会一直阻塞,直到读取到至少一个数据包为止。如果没有数据可读取,函数会等待直到超时或者数据到达。

优点:阻塞模式能够确保接收所有的数据包,并且对于网络状况不稳定的情况下,可以保证数据的正常获取。

缺点:在没有数据到达时,该方式可能会浪费较多的资源。

非阻塞模式
在非阻塞模式下,recvfrom函数会立即返回。如果有数据可读取,函数返回读取到的字节数。否则,函数会返回错误代码EAGAIN或EWOULDBLOCK,表示当前没有数据可读取。

优点:非阻塞模式避免了等待时间过长的问题,并且能够更加灵活地处理数据包的接收。

缺点:需要额外的代码实现来避免在无数据时的过度循环,并且对于网络状况不佳的情况,可能会导致数据丢失。

Windows下使用UDP的recvfrom函数设置超时时,如果recvfrom函数没有接收到数据,会阻塞等待直到超时或者数据到达。如果您设置的超时时间过长,可能会导致程序一直等待,无法退出。

解决这个问题的方法是,使用Windows下提供的另外一个函数来实现超时功能,例如:

int nRecvSize = 0;
fd_set fdRead;
FD_ZERO(&fdRead);
FD_SET(m_nRecvSockFd, &fdRead);
timeval timeout = {0, RECVTIMEOUT}; // 设置超时时间
int nRet = select(m_nRecvSockFd + 1, &fdRead, NULL, NULL, &timeout);
if (nRet < 0) {
    // select 函数调用失败
    return false;
} else if (nRet == 0) {
    // 超时
    return false;
} else {
    // 有数据可读取
    nRecvSize = recvfrom(m_nRecvSockFd, ...);
    ...
}

这里使用了Windows下的select函数来实现超时功能。首先,将UDP套接字加入到fdRead集合中,然后调用select函数等待数据到达或者超时。如果select函数返回0,表示超时;如果返回-1,表示调用失败;如果返回大于0,表示有数据可读取,此时调用recvfrom函数来接收数据。

另外,您提到使用阻塞模式来接收UDP数据能够减少丢包,这是因为阻塞模式能够确保接收所有的数据包,但是会浪费较多的资源。如果您的应用程序需要处理高并发的UDP数据,建议使用非阻塞模式来处理,以提高系统的性能和稳定性。