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 を使用するのは悪い考えのようです。何か不足していますか?

4

1 に答える 1