select, recv и завершение соеденения

Тема в разделе "WASM.NETWORKS", создана пользователем Aspire, 2 сен 2008.

  1. Aspire

    Aspire New Member

    Публикаций:
    0
    Регистрация:
    19 май 2007
    Сообщения:
    1.028
    Есть серверное приложение, работающее с неблокирующими сокетами.
    Заряжаем select на готовность данных для чтения, она будет успешна даже в том случае, если соеденение завершено.
    Дальше, вызываем recv, который после принятия всей порции данных, опять же в цикле после select, возвращает ноль, но соеденение никто не закрывал! (при этом теряется весь смысл вызова select, в данном случае)
    Клиент просто висит в ожидании.
    1. Может быть, утверждение "If the connection has been gracefully closed, the return value is zero" верно только для блокирующих сокетов?
    2. Почему recv возвращает 0?
    3. Как в моем случае понять, что соеденение действительно завершилось?

    С уважением.
     
  2. Aspire

    Aspire New Member

    Публикаций:
    0
    Регистрация:
    19 май 2007
    Сообщения:
    1.028
    Видимо, ждем leo или nester7 :)
     
  3. s0larian

    s0larian New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2004
    Сообщения:
    489
    Адрес:
    Крыжёпполь
    recv() возвращает SOCKET_ERROR, ноль или размер данных в байтах. Для blocking sockets последующий вызов просто блокирует поток, для non blocking получишь назад ошибку ...WOULDBLOCK.

    Обычно используются blocking socket + select() или non blocking + overlapped IO (completion ports). В первом случае ты просто вызываешь send() - пусть от будет blocking, но не должен вызывать recv() пока не пулучишь сигнал от select().
     
  4. TarasCo

    TarasCo New Member

    Публикаций:
    0
    Регистрация:
    2 фев 2005
    Сообщения:
    106
    Это неправильно утверждение. recv вернет 0 в том случае, если удаленный хост закрыл свою половину соединения ( помним, что TCP дуплексный протокол; он может работать в полузакрытом состоянии, когда данные передаются только в одну сторону ). "has been gracefully closed" - это значит, что соединение полностью закрыто, т.е обе стороны вызвали shutdown ( s, SD_SEND ), что приводит к послыке FIN пакета.

    Потому что ваш хост получил FIN пакет от другой стороны, можете убедиться в этом с помощью сниффера ( это 100% так, если конечно это не баг в вашем коде ).

    Противоположенная сторона закрыла свою половину соединения и теперь ждет этого от вас. В принципе, вы можете продолжать передавать данные, но обычно протоколы не работают в с полузакрытыми соединениями, поэтому разумно в данной ситуации вызвать:
    shutdown ( s, SD_SEND );
    closesocket( s );

    Вызов shutdown можно опустить, если вы не трогали опцию SO_LINGER