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