简体   繁体   English

为什么windows udp接收套接字的超时总是比SO_RCVTIMEO设置的时间长500毫秒?

[英]Why is the timeout on a windows udp receive socket always 500ms longer than set by SO_RCVTIMEO?

Easy to reproduce, here is the psuedo code of what i am doing: 易于重现,这是我正在做的psuedo代码:

  1. Set up a UDP socket 设置UDP套接字
  2. Set the timeout to a value ( Timeout set ) Timeout set为值( Timeout set
  3. Check the timeout that I set ( Timeout checked ) 检查我设置的超时( Timeout checked
  4. Attempt to receive on that socket (when there is no traffic). 尝试在该套接字上接收(当没有流量时)。
  5. Time how long it takes to timeout. 超时需要多长时间。 ( Time until Timeout ) Time until Timeout

When I do this i get the following output: 当我这样做时,我得到以下输出:

Timeout set: 0.1s | Timeout checked: 0.1s | Time until timeout: 0.6s | difference: 0.5s
Timeout set: 0.2s | Timeout checked: 0.2s | Time until timeout: 0.7s | difference: 0.5s
Timeout set: 0.4s | Timeout checked: 0.4s | Time until timeout: 0.9s | difference: 0.5s
Timeout set: 0.8s | Timeout checked: 0.8s | Time until timeout: 1.3s | difference: 0.5s
Timeout set: 1.6s | Timeout checked: 1.6s | Time until timeout: 2.1s | difference: 0.5s
Timeout set: 3.2s | Timeout checked: 3.2s | Time until timeout: 3.7s | difference: 0.5s

Why does the windows udp socket timeout always run 500ms longer than that set in setsockopt? 为什么windows udp套接字超时总是比setsockopt中设置的时间长500ms?

Looking at setsockopt here I can see no information about why this is occurring under the sections involving SO_RCVTIMEO . 这里查看setsockopt我看不到有关为什么在涉及SO_RCVTIMEO的部分下发生这种情况的信息。


Code to reproduce: 代码重现:

#include "stdafx.h"
#include "winsock2.h"
#include <chrono>
#include <iostream>

int main() {
    WORD wVersionRequested;
    WSADATA wsaData;

    wVersionRequested = MAKEWORD(2, 2);
    int err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        printf("WSAStartup failed with error: %d\n", err);
        while (true);
    }

    sockaddr_in socketAddress = { 0 };
    socketAddress.sin_family = PF_INET;
    socketAddress.sin_port = htons(1010);
    socketAddress.sin_addr.s_addr = INADDR_ANY;

    // Create the socket
    SOCKET mSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (!mSocket) { 
        printf("Socket failed with error code : %d", WSAGetLastError());
        while (true);
    }

    //Bind
    if (bind(mSocket, (struct sockaddr *)&socketAddress, sizeof(socketAddress)) == SOCKET_ERROR) {
        printf("Bind failed with error code : %d", WSAGetLastError());
        while (true);
    }

    // Receive nothing over several different set timeouts
    for (double timeout = 0.1; timeout < 4.0; timeout *= 2) {

        // Set timeout
        DWORD lBuffer[2] = { 0, 0 };
        int lSize;
        lBuffer[0] = static_cast<DWORD>(1000.0 * timeout);
        lSize = sizeof(DWORD);
        if (setsockopt(mSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)lBuffer, lSize) != 0) {
            printf("Set socket option failed with error code : %d", WSAGetLastError());
            while (true);
        }

        // Check that we get what we set.
        DWORD lBufferout[2] = { 0, 0 };
        if (getsockopt(mSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)lBufferout, &lSize) != 0) {
            printf("Set socket option failed with error code : %d", WSAGetLastError());
            while (true);
        }

        // Receive and time
        char buffer[50];
        sockaddr_in senderAddr;
        int senderAddrSize = sizeof(senderAddr);

        auto s = std::chrono::steady_clock::now();

        int transferred = recvfrom(mSocket, (char*)buffer, 50, 0,
            (sockaddr*)&senderAddr, &senderAddrSize);

        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - s).count() / 1000.0;

        std::cout << "Timeout set: " << timeout << "s | Timeout checked: " << lBufferout[0] / 1000.0 << "s | Time until timeout: " << duration << "s | difference: " << duration - timeout << "s\n";
    }

    while (true);

    return 0;
}

Note: This code is expecting there to be no traffic on port 1010. If this is not the case, change that number. 注意:此代码期望端口1010上没有流量。如果不是这种情况,请更改该号码。

It is stated here: 这里说明

There is an undocumented minimum limit of about 500mS on SO_RCVTIMEO. SO_RCVTIMEO上的无证件最低限制约为500mS。

It is likely that this is implemented by always adding 500ms to any value set for SO_RCVTIMEO . 这是可能的,这通过总是加上500毫秒为设置的任何值实现SO_RCVTIMEO

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM