Программирование сокетов - сомнения в API

Сегодня в классе был опубликован вопрос о дизайне API в программировании сокетов.

Почему listen() и accept() представлены как разные функции, а не объединены в одну?

Теперь, насколько мне известно, listen помечает подключенный сокет как готовый принимать соединения и устанавливает максимальную границу очереди входящих соединений. Если accept и listen объединены, может ли такая очередь не поддерживаться?

Или есть какое-то другое объяснение?

Заранее спасибо.


person cowboybebop    schedule 06.02.2011    source источник


Ответы (3)


  • listen() означает "начать слушать клиентов"
  • accept() означает "принять клиента, блокируя его до тех пор, пока он не подключится, если это необходимо"

Имеет смысл разделить эти два, потому что, если бы они были объединены, то одна объединенная функция заблокировалась бы. Это может вызвать проблемы для неблокирующих программ ввода/вывода.

Например, возьмем типичный сервер, который хочет прослушивать новые клиентские подключения, а также отслеживать существующие клиентские подключения на наличие новых сообщений. Такой сервер обычно использует неблокирующую модель ввода-вывода, поэтому он не блокируется ни на одном конкретном сокете. Поэтому ему нужен способ «начать прослушивание» серверного сокета, не блокируя его. После того, как прослушивание серверного сокета было инициировано, серверный сокет добавляется в группу сокетов, отслеживаемых через select() (называемый poll() в некоторых системах). Вызов select() будет указывать, когда клиент находится в ожидании на сокете сервера. Затем программа может вызывать accept(), не опасаясь блокировки этого сокета.

person Bert F    schedule 06.02.2011
comment
О, я так и предполагал. Я думал, что нельзя поддерживать много соединений одновременно. Спасибо. - person cowboybebop; 06.02.2011
comment
@ryan рад помочь - person Bert F; 06.02.2011

listen(2) делает данный сокет TCP < em>серверный сокет, т.е. создает очередь для приема запросов на подключение от клиентов. Только порт прослушивающей стороны и, возможно, IP-адрес привязаны (поэтому вам нужно вызвать bind(2) перед listen(2)). accept(2) фактически принимает такой запрос на подключение из этой очереди и превращает ее в подключенный сокет (назначаются четыре части, необходимые для двусторонней связи: IP-адрес источника, номер порта источника, IP-адрес назначения и номер порта назначения). listen(2) вызывается только один раз, а accept(2) обычно вызывается несколько раз.

person Nikolai Fetissov    schedule 06.02.2011

Под капотом bind присваивает адрес и порт дескриптору сокета. Это означает, что порт теперь зарезервирован для этого сокета, и поэтому система не сможет назначить тот же порт другому приложению (существует исключение, но я не буду здесь вдаваться в подробности). Это также однократная операция для каждого сокета.

Затем listen отвечает за установление количества соединений, которые могут быть поставлены в очередь для данного дескриптора сокета, и указывает, что теперь вы готовы принимать соединения.

С другой стороны, accept используется для удаления первого соединения из очереди ожидающих соединений и создания нового сокета для обработки дальнейшего взаимодействия через него. Его можно вызывать несколько раз, и обычно это так. По умолчанию эта операция блокируется, если в очереди нет подключений.

Теперь предположим, что вы хотите использовать механизм асинхронного ввода-вывода (например, epoll, poll, kqueue, select и т. д.). Если бы listen и accept были одним API, как бы вы указали, что данный сокет готов принимать соединения? Асинхронный механизм должен знать, что вы также хотите обрабатывать события этого типа.

Имея совершенно разную семантику, имеет смысл разделить их.

person jweyrich    schedule 06.02.2011