Правильный способ закрыть блокирующий сокет UDP - PullRequest
9 голосов
/ 10 июня 2011

У меня есть объект C ++, который создает поток для чтения из блокирующего сокета UDP:

mRunning.store(true);
while (mRunning.load(boost::memory_order_consume)) {
    ...
    int size = recvfrom(mSocket, buf, kTextBufSize , 0,
                        (struct sockaddr *) &packet->mReplyAddr.mSockAddr, (socklen_t*)&packet->mReplyAddr.mSockAddrLen);

    if (size > 0) {
        //do stuff
    }
}
return 0;

(mRunning - это импульс :: атомный) Деструктор объекта вызывается из другого потока и делает это:

mRunning.store(false);  
#ifdef WIN32
    if (mSocket != -1) closesocket(mSocket);
#else
    if (mSocket != -1) close(mSocket);
#endif
pthread_join(mThread, NULL);

Кажется, это работает, но один из моих коллег предположил, что может возникнуть проблема, если recv прерывается во время чтения чего-либо. Эта тема безопасна? Как правильно закрыть блокирующий UDP-сокет? (Должен быть кроссплатформенным OSX / Linux / Windows)

Ответы [ 3 ]

5 голосов
/ 10 июня 2011

Там может быть много разных проблем.Перемещая мое приложение из одной версии FreeBSD в другую, я обнаружил, что такой close () нормально работал на старом ядре и просто зависал close (), пока что-то не вернулось из recv () на более новой.А OSX основан на FreeBSD:)

Переносимый способ закрытия сокетов из другого потока состоит в создании канала и блока не в recv (), а в select ().Когда вам нужно закрыть сокет, напишите что-нибудь в pipe, select () разблокирует, и вы можете безопасно сделать close ().

1 голос
/ 10 июня 2011

Ну recvfrom само по себе является поточно-ориентированным.IIRC все функции сокета есть.Вопрос в следующем:

  • Что произойдет, если вы извлечете дескриптор из-под recvfrom во время копирования данных в буфер?

Это хорошо хорошовопрос но я сомневаюсь, что в стандарте об этом сказано что-либо (я также сомневаюсь, что конкретное руководство по реализации что-нибудь говорит об этом).Таким образом, любая реализация может:

  • завершить операцию (возможно, потому, что ей больше не нужен дескриптор, или потому что она выполняет какой-то классный подсчет ссылок или что-то еще)
  • Makerecvfrom завершается ошибкой и возвращает -1 (ENOTSOCK, EINVAL?)
  • Эффектно падает, поскольку буферы и внутренние структуры данных освобождаются close.

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

Итак, что вы можете сделать?Самое безопасное: используйте механизм синхронизации, чтобы убедиться, что вы только close сокет после recvfrom (семафоры, мьютексы и т. Д.).

Лично я бы сделал UP на семафор послеrecvfrom и DOWN до close.

0 голосов
/ 10 июня 2011

Ваш коллега прав, бустовые розетки не безопасны для потоков.

Ваши параметры;

  1. Использовать ASIO (сделайте это)
  2. Тайм-аут при блокировке вызова.Это на самом деле не переносимо, хотя может работать.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...