2013-10-16 50 views
1

我在写一个需要创建UDP套接字以接收数据报的MFC \ C++程序。 我正在使用阻塞套接字(出于性能原因),并在尝试设置接收调用超时时出现一些错误(或误解)。在接收问题上阻塞套接字超时

当我使用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我注意到如下:

如果发送或接收操作超时在套接字上,套接字状态是不确定的,不应该是使用...“

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

+0

仅供参考当我在Win8上使用VS2012运行你的代码我得到大致正确的时间,每次等待94-109ms。 – mark

+0

MSDN不正确或至少不准确。读取超时后,套接字仍然连接,仍然可以用于进一步的I/O。经过*写入*超时后,套接字几乎肯定会死机,如果再次使用,会引发ECONNRESET。 – EJP

回答

0

使用'timeval'stuct初始化超时值。

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