Если неблокирующий recv с MSG_PEEK будет успешным, будет ли успешным последующий recv без MSG_PEEK? - PullRequest
11 голосов
/ 14 мая 2009

Вот упрощенная версия кода, над которым я работаю:

void
stuff(int fd)
{
    int ret1, ret2;
    char buffer[32];

    ret1 = recv(fd, buffer, 32, MSG_PEEK | MSG_DONTWAIT);

    /* Error handling -- and EAGAIN handling -- would go here.  Bail if
       necessary.  Otherwise, keep going.  */

    /* Can this call to recv fail, setting errno to EAGAIN?  */
    ret2 = recv(fd, buffer, ret1, 0);
}

Если мы предположим, что первый вызов recv завершился успешно, возвращая значение от 1 до 32, безопасно ли предположить, что второй вызов также будет успешным? Может ли ret2 быть меньше, чем ret1? В каких случаях?

(Для ясности предположим, что во время второго вызова recv нет других условий ошибки: сигнал не доставлен, он не установит ENOMEM и т. Д. Также предположим, что другие потоки не будут смотреть на fd.

Я работаю в Linux, но, как мне кажется, MSG_DONTWAIT - единственная вещь, специфичная для Linux. Предположим, что правильный fnctl был ранее установлен на других платформах.)

Ответы [ 5 ]

8 голосов
/ 15 мая 2009

Стандарт POSIX указывает, что в MSG_PEEK «данные считаются непрочитанными, и следующая функция recv () или аналогичная функция все равно будет возвращать эти данные». Похоже, это означает, что если ret2 не равен -1, он будет таким же, как ret1.

5 голосов
/ 15 мая 2009

Вы также должны учитывать возможность того, что другой вызов recv в другом потоке может быть вызван между ret1 и ret2. Этот другой вызов получит ваши данные, оставив ret2 без данных или неожиданно меньше данных.

Если ваше приложение не многопоточное или разработано так, что fd используется только этими двумя вызовами, то вы можете проигнорировать это. Но если это риск, то вы должны поместить два вызова в механизм блокировки.

2 голосов
/ 22 декабря 2010

Ваш второй вызов recv () без MSG_PEEK может завершиться с ошибкой EINTR или вернуть неполные данные, поскольку они были прерваны сигналом.

1 голос
/ 14 мая 2009

Я не уверен насчет EAGAIN, но думаю, что возможны EBADF или ECONNRESET.

0 голосов
/ 08 июля 2009

В вашем простом случае последующий recv вернет число байтов ret1 (если ret1 не было ошибкой). Однако для многопоточного дизайна это не всегда может быть правдой.

...