Выбор сокета UDP() возвращает 1 без задержки (тайм-аут) при некоторых условиях.

Я столкнулся с проблемой во время разработки моего клиентского приложения.

Я хочу использовать неблокирующие сокеты UDP в своем приложении для связи с сервером. Я использую библиотеку winsock2 в Windows.

Но... Почему-то у меня странное поведение функции select() при некоторых условиях:

  1. Сокет не имеет привязанного адреса и порта (это сокет на стороне клиента, поэтому он не нужен).
  2. Before select() I send data to my local address and some port with sendto call.
    • For example: 192.168.1.2

В этих условиях select() мгновенно (даже не дожидаясь тайм-аута) возвращает 1. Как будто у меня есть какой-то пакет, готовый к приему. Но если вызвать recvFrom, то он обязательно вернет -1.


  1. Если я отправляю свои пакеты от клиента на любой другой адрес (который не является моим адресом в локальной сети), тогда select() работает по назначению.
  2. Также select() работает по назначению, если не отправлять пакеты на любой адрес перед вызовом select().

Метод инициализации сокета:

bool CUdpSocket::initialize()
{
  _handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

  ... error processing code, returns false if error...
}

Метод, который использует select(). Этот метод отлично работает для сокета сервера (с привязанным адресом и портом).

bool CUdpSocket::waitData(s32 timeout_ms)
{
    fd_set readset;
    int result;
    struct timeval tv;

    // Initialize the set.
    FD_ZERO(&readset);
    FD_SET(_handle, &readset);

    // Initialize time out struct.
    tv.tv_sec = 0;
    tv.tv_usec = timeout_ms * 1000;

    result = select(_handle + 1, &readset, NULL, NULL, &tv);

    // Timeout with no data.
    if (result == 0) {
        return false; // Get out of here!
    }

    // Error.
    if (result < 0) {
        // TODO: Maybe throw exception or do something.
        return false;
    } else if (!FD_ISSET(_handle, &readset)) {
        return false; // No data!
    }

    // There is some data!
    return true;
}

person zcaliptium    schedule 30.06.2018    source источник
comment
comment
recvfrom() вернет -1 с какой ошибкой?   -  person user207421    schedule 30.06.2018
comment
@EJP Хммм ... Забыл это проверить. WSAGetLastError после вызова recvFrom возвращает код 10054 (WSAECONNRESET).   -  person zcaliptium    schedule 30.06.2018
comment
Google — ваш друг: Google WSAECONNRESET UDP — лучший результат: stackoverflow.com/questions/30749423/, согласно комментарию @ChrisDodd ниже. Надеюсь, из этого вы узнали что-то о том, как копаться в собственных проблемах.   -  person Paul Sanders    schedule 03.07.2018


Ответы (1)


Если вы отправляете пакет из несвязанного сокета UDP, ОС выберет для вас используемый порт и привяжет сокет к этому порту — протокол UDP требует, чтобы у отправляющего порта был адрес для отправки .

Таким образом, если пакет, который вы отправляете, приводит к ответу, то имеет смысл выбрать возврат 1 — это ответ на отправленный вами пакет.

person Chris Dodd    schedule 30.06.2018
comment
Как я писал. Проблема в том... Я постоянно получаю возврат 1, даже если серверное приложение не запущено (нет ответа). И select() мгновенно возвращает 1. Не дожидаясь окончания тайм-аута. Это происходит только в том случае, если адрес, на который я отправляю адрес запроса, является адресом моей локальной сети. - person zcaliptium; 30.06.2018
comment
Если сервер не работает, вы можете получить ответ об ошибке ICMP от операционной системы. В этом случае это может отображаться как ошибка принимающего сокета. - person Chris Dodd; 30.06.2018