Server vs Client Socket (сведения о низком уровне)?

Общее программирование: в методе accept() сервера socket, что именно происходит. На низком уровне, насколько серверные сокеты отличаются от клиентских сокетов?

Ответ 1

Во-первых, серверные сокеты обычно связаны с известными именами (в этом случае порты), и они устанавливаются с помощью listen(). Именно здесь происходит реальная разница, так как клиентские сокеты устанавливаются с помощью connect(). Вызов listen() в сокете приводит к тому, что реализация tcp/ip ядра начнет принимать соединения, отправленные в имя привязки сокета (порт). Это произойдет независимо от того, вы когда-либо звонили accept().

accept() просто дает вашему серверу способ доступа и взаимодействия с клиентскими сокетами, которые подключены к вашему гнезду для прослушивания.

Ответ 2

На низкоуровневых сокетах есть только сокеты, независимо от того, используются ли они в сервере или клиентском приложении. Разница между двумя лежит в системных вызовах каждого типа приложений.

Сокеты сервера вызовут bind() для связи с портом. Они хотят быть связанными с портом, чтобы другие программы знали, где их можно найти. Клиентские сокеты могут вызывать bind(), но почти никогда не выполняются, потому что не так много точек. Если сокет не вызывает bind(), ОС просто выберет для него эфемерный порт, что отлично подходит для клиентов, поскольку они выполняют вызов; никто не должен их называть.

Вызов сокетов сервера listen(). Это было хорошо объяснено в других ответах.

Вызов сокетов сервера accept(), и я думаю, что это суть вашего вопроса, потому что сначала это немного загадочно. Важно понять, что при вызове accept() ядро ​​вернет новый сокет. Теперь он отделен от оригинального сокета для прослушивания и является тем, что ваш сервер будет использовать для связи со своими одноранговыми узлами.

Ключ в понимании того, как прослушивающий сокет продолжает прослушиваться, когда принятое соединение выполняет свою задачу, заключается в понимании того, что соединения tcp зависят от 4-парного (1) локального адреса (2) локального порта (3) постороннего адреса (4) иностранный порт. Они определяют уникальное соединение. До того, как accept() передал новый сокет, ядро ​​использовало эти значения для создания различных структур, чтобы в сотрудничестве с стеком tcp/ip весь трафик с этим кортежем переходил к подключенному сокету. Даже если ваш сервер может иметь тысячу соединений с локальным адресом 192.168.1.100, порт 80, клиентская комбинация адреса и порта всегда будет отличаться и, следовательно, кортеж всегда уникален.

Ответ 3

Если вы действительно заинтересованы, я бы посоветовал вам прочитать TCP/IP Illustrated, том 2. Если вы хотите получить меньше ответов "в кишках", то:

  • Сокеты сервера привязаны к хорошо известным конечным точкам, где конечная точка является кортежем (протокол, адрес, порт). Конечная точка формируется протоколом, указанным в системном вызове socket(), и информацией адресации, указанной в системном вызове bind().
  • Когда сервер вызывает системный вызов listen(), сетевой стек создает очередь, в которую помещаются ожидающие подключения. Подсказка к размеру очереди указывается как параметр backlog на listen().
  • Затем сервер вызывает accept(), чтобы вытащить новое соединение из очереди.
  • Сокеты клиента отправляют сообщения в сокеты сервера, указывая конечную точку сервера при вызове connect(), а затем отправляя данные с помощью send() или write().
  • Когда клиент вызывает connect(), соединение переносится в очередь на стороне сервера, где он сидит, пока сервер не примет соединение.

Это описание действительно действительно действительно только для сокетов TCP/IP. Случай UDP проще и совсем другой, поскольку сокеты UDP не связаны (обязательно).

Ответ 4

Трудно полностью ответить на ваш вопрос, не указав язык программирования. Я отвечу на python, потому что для всех, кого я знаю, ответ может быть репрезентативным.

Если s является объектом socket, тогда сервер сначала связывается с портом, вызывая s.bind(('',12345)). Это создает сокет в режиме сервера. Он подготовлен для сбора данных на порте 12345.

Затем вызывается s.listen(10). Это выдает сокет в режим сервера. Это означает, что запрос на соединение будет получен этим сокетом (до 10 ожидающих запросов одновременно).

К моменту, когда мы доходим до s.accept(), операционная система уже знает, что мы слушаем порт 12345. s.accept() просто говорит, что мы будем делать с запросами, которые мы получаем. В python s.accept() вернет (connection,address), где соединение - это соединение через другой порт. В этом случае connection не сильно отличается от объекта сокета, который клиент открыл. Это разумно симметрично отсюда.