c++ - 在接收问题上阻塞套接字超时

标签 c++ sockets networking

我正在编写一个 MFC\C++ 程序,它需要创建一个 UDP 套接字来接收数据报。 我正在使用阻塞套接字(出于性能原因),并且在尝试为接收调用设置超时时遇到一些错误(或误解)。

当我使用 setsockopt() 将接收超时设置为 100mili 并且接收确实超时时 - 它在大约 600mili 后超时。

当我使用 setsockopt() 将接收超时设置为 1000mili 并且接收确实超时时 - 它在大约 1600mili 后超时。

这是为什么? 我做错了什么吗?

我的代码是这样的:

WSADATA              wsaData;
SOCKET               ReceivingSocket;
SOCKADDR_IN          ReceiverAddr;
int                  Port = 2345;
char                 ReceiveBuf[1024];
int                  BufLength = 1024;
SOCKADDR_IN          SenderAddr;
int                  SenderAddrSize = sizeof(SenderAddr);
int                  Ret;

// 100mili timeout
int RecvTimeout = 100 ;

// Initialize Winsock version 2.2
if ((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)
{
    TRACE("ERROR: WSAStartup failed with error %d\n", Ret);
    return;
}

// Create a new socket to receive datagrams
if ((ReceivingSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))
    == INVALID_SOCKET)
{
    TRACE("ERROR: socket failed with error %d\n", WSAGetLastError());
    WSACleanup();
    return;
} 

// receive datagrams from all interfaces using port 2345
ReceiverAddr.sin_family = AF_INET;
ReceiverAddr.sin_port = htons(Port);    
ReceiverAddr.sin_addr.s_addr = htonl(INADDR_ANY);

// bind
if (bind(ReceivingSocket, (SOCKADDR *)&ReceiverAddr, sizeof(ReceiverAddr))
    == SOCKET_ERROR)
{
    TRACE("ERROR: bind failed with error %d\n", WSAGetLastError());
    closesocket(ReceivingSocket);
    WSACleanup();
    return;
}

// set receive timeout
if ( setsockopt (
    ReceivingSocket,
    SOL_SOCKET,
    SO_RCVTIMEO,
    (const char*)&RecvTimeout,
    sizeof(RecvTimeout) ) == SOCKET_ERROR )
{
    TRACE("Error using setsockopt\n") ;
    closesocket(ReceivingSocket);
    WSACleanup();
    return;
}

// Receive 10 messages - here the timeout comes to life...
for(int i = 0 ; i < 10 ; i++)
{
    TRACE("Before Recv, Ticks=%d\n", GetTickCount()) ;
    if ((Ret = recvfrom(ReceivingSocket, ReceiveBuf, BufLength, 0,
        (SOCKADDR *)&SenderAddr, &SenderAddrSize)) == SOCKET_ERROR)
    {
        if(WSAETIMEDOUT == WSAGetLastError())
            TRACE("After Recv, Ticks=%d\n\n", GetTickCount()) ;
        else
        {
            TRACE("ERROR: receive failed with error %d\n", WSAGetLastError());
            closesocket(ReceivingSocket);
            WSACleanup();
            return;
        }
    }
}

closesocket(ReceivingSocket);
WSACleanup();

我得到的输出是这样的:

Before Recv, Ticks=1476485406
After Recv, Ticks=1476486031

Before Recv, Ticks=1476486031
After Recv, Ticks=1476486656

Before Recv, Ticks=1476486656
After Recv, Ticks=1476487281
.
.
.

此外,当我查看 MSDN 以了解有关 SO_RCVTIMEO 的更多信息时,我注意到以下内容:

If a send or receive operation times out on a socket, the socket state is indeterminate, and should not be used..."

所以基本上使用 SO_RCVTIMEO 似乎是一个坏主意,如果我真的超时了。 我错过了什么吗?

最佳答案

使用'timeval'结构来初始化超时值。

struct timeval timeout;
timeout.tv_sec = SOCKET_READ_TIMEOUT_SEC; // in milli secs
timeout.tv_usec = 0; 

关于c++ - 在接收问题上阻塞套接字超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19398088/

相关文章:

c++ - 是在 Mac 上使用 libc++ 或 libstdc++ 构建的库

c++ - 将指针变量设置为多个值

sockets - 增强async_read_some/async_receive的行为就像MSG_PEEK始终处于打开状态

c++ - 将 IP 地址从 sockaddr_in6 转换为 in_addr

django - 守护进程 Django 管理命令

ios - 如何显示未完全加载的图像的缩略图

c++ - windows linux 时间戳 c++ 错误

c++ - 即使在 pop() 之后,STL stack top() 函数也读取相同的值。

c++ - 在 boost::asio 中为 SSL/TLS 使用特定密码

iPhone HTTP 服务器