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似乎是一个坏主意,如果我得到超时。 我错过了什么吗?
仅供参考当我在Win8上使用VS2012运行你的代码我得到大致正确的时间,每次等待94-109ms。 – mark
MSDN不正确或至少不准确。读取超时后,套接字仍然连接,仍然可以用于进一步的I/O。经过*写入*超时后,套接字几乎肯定会死机,如果再次使用,会引发ECONNRESET。 – EJP