Как сервер узнает, на какой клиентский порт отправлять?

26

Насколько я понимаю, это то, что происходит, когда клиент делает запрос на соединение:

  1. Сервер будет привязан к определенному номеру порта. Номер порта всегда привязан к процессу прослушивания. Поскольку только сервер прослушивает входящие соединения, нам не нужно связываться на стороне клиента
  2. Сервер продолжит прослушивание этого номера порта.
  3. Клиент отправит connect()запрос.
  4. Сервер примет запрос, используя accept(). Как только сервер принимает запрос клиента, ядро ​​выделяет случайный номер порта для сервера для дальнейшего send()и receive(), поскольку один и тот же номер порта на сервере не может использоваться для отправки и прослушивания, а предыдущий порт все еще прослушивание новых связей

Учитывая все это, как сервер узнает, на какой порт получает клиент? Я знаю, что клиент будет отправлять сегменты TCP с портом источника и портом назначения, поэтому сервер будет использовать порт источника этого сегмента в качестве порта назначения, но какую функцию вызывает сервер, чтобы узнать об этом порте? Это accept()?

Суби Суреш
источник
Связанный: stackoverflow.com/questions/14388706/…
Pacerier

Ответы:

33

Это часть заголовка TCP (или UDP и т. Д.) В пакете. Таким образом, сервер узнает, потому что клиент говорит это. Это похоже на то, как он узнает IP-адрес клиента (который является частью заголовка IP).

Например, каждый пакет TCP включает заголовок IP (по крайней мере, с исходным IP, целевым IP и протоколом [TCP]). Затем есть заголовок TCP (с портом источника и назначения, плюс еще).

Когда ядро ​​получает пакет SYN (начало соединения TCP) с удаленным IP-адресом 10.11.12.13 (в заголовке IP) и удаленным портом 12345 (в заголовке TCP), оно знает удаленный IP-адрес и порт , Он отправляет обратно SYN | ACK. Если он получает ACK обратно, listenвызов возвращает новый сокет, настроенный для этого соединения.

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

Как правило, локальный порт и локальный IP будут одинаковыми для всех подключений к процессу сервера (например, все подключения к sshd будут на local-ip: 22). Если один удаленный компьютер устанавливает несколько соединений, каждое из них будет использовать другой удаленный порт. Так что все, кроме удаленного порта, будет таким же, но это нормально - только один из четырех должен отличаться.

Вы можете использовать, например, wirehsark, чтобы увидеть пакет, и он пометит все данные для вас. Вот выделенный порт источника (обратите внимание, что он выделен в декодированном пакете, а также шестнадцатеричный дамп внизу):

Wireshark показывает пакет TCP SYN

derobert
источник
Спасибо за объяснение. Итак, вы хотели сказать, что новый дескриптор сокета сервера (т. Е. Кортеж), полученный после accept (), будет содержать данные о клиентском порте и адресе клиента, и с помощью этого нового сервера дескриптора сокета отправляет и получает данные и из client.New дескриптор файла сокета будет иметь новый номер порта сервера, назначенный ядром, ip сервера, ip клиента и порт клиента. Я прав?
Суби Суреш
@SubiSuresh Да, кортеж хранится в ядре, связанном с этим файловым дескриптором.
Дероберт
> Спасибо derobert.So я заключаю, что новый дескриптор сокета сервера будет иметь клиентский порт и адрес клиента, который сервер получает от accept (). Мое понимание хорошо, верно?
Суби Суреш
@SubiSuresh Да, это правильно. С точки зрения приложения, вам обычно все равно (кроме регистрации). Ядро следит за тем, чтобы данные, которые вы write(и т.д.) отправляли в нужное место.
Дероберт
> Спасибо за вашу помощь, и я думаю, что понял. ;-)
Суби Суреш
2

«Запрос на подключение ( connect()обычно системный вызов клиентской программы ) вызывает трехстороннее рукопожатие . Первый пакет трехстороннего рукопожатия (от клиента к серверу) имеет установленный флаг SYN и включает номер порта TCP клиентской программы. ядро присваивает ему.

Вы можете увидеть это в статье о пакетах Nmap и Natural SYN . Декодирование пакета Nmap SYN имеет фразу «source.60058> dest.22». Декодирование «законный пакет SYN» содержит фразу «source.35970> dest.80». Два пакета SYN сообщают удаленному ядру, что пакеты поступают с порта TCP 60058 и порта 35970 соответственно.

Брюс Эдигер
источник
> Но, Брюс, это происходит на заднем плане. Но как мой сервер на самом деле выбирает такие детали, как номер порта, потому что обычно в клиент-серверных программах я никогда не видел никакой функции для извлечения клиентского порта и адреса клиента
Суби Суреш,
Системный вызов getpeername()должен позволить вам сделать это на любом открытом сокете. accept()Системный вызов , что код сервера должен использовать , чтобы получить дескриптор файла сокета обратной связи с клиентом имеет параметр ( «SOCKADDR» в моих мужских страницах), содержащий IP - адрес потенциального клиента и TCP номер порта.
Брюс Эдигер
> Пожалуйста, не возражайте, если я elloborate. Из всех введенных мною данных я понял, что accept () имеет структуру sockaddr_in, заполненную деталями клиента, а новый дескриптор сокета сервера, возвращаемый после accept (), будет автоматически иметь клиентский порт и адрес. Вот почему мы можем отправлять сообщения с помощью send (новый дескриптор сокета сервера). Надеюсь, я дошел до сути? Это просто для того, чтобы убедиться, что то, что я понял, правильно.
Суби Суреш
@SubiSuresh - я полагаю, ты написал правду.
Брюс Эдигер
1

TCP-сокет является потоково-ориентированным сокетом. Два дескриптора сокета (принадлежащие вам и вашему партнеру) надежно связаны. Так что вам не нужно беспокоиться о порте клиента - просто напишите свой дескриптор сокета!

Кроме того, не стесняйтесь getockname (2), если вы действительно хотите это знать (возможно, для регистрации).

b166er
источник
0

Соединение определяется кортежем (исходный IP-адрес, исходный порт, IP-адрес назначения, порт назначения). Ответы идут наоборот.

vonbrand
источник
@vondrand В этом пункте я понял von. Но из какой функции сервер узнает о номере порта клиента? Не зная номер порта клиента, как он будет отправлять. Так что сервер использует структуру в accept () для извлечения клиента порт?
Суби Суреш