Насколько я понимаю, это то, что происходит, когда клиент делает запрос на соединение:
- Сервер будет привязан к определенному номеру порта. Номер порта всегда привязан к процессу прослушивания. Поскольку только сервер прослушивает входящие соединения, нам не нужно связываться на стороне клиента
- Сервер продолжит прослушивание этого номера порта.
- Клиент отправит
connect()
запрос. - Сервер примет запрос, используя
accept()
. Как только сервер принимает запрос клиента, ядро выделяет случайный номер порта для сервера для дальнейшегоsend()
иreceive()
, поскольку один и тот же номер порта на сервере не может использоваться для отправки и прослушивания, а предыдущий порт все еще прослушивание новых связей
Учитывая все это, как сервер узнает, на какой порт получает клиент? Я знаю, что клиент будет отправлять сегменты TCP с портом источника и портом назначения, поэтому сервер будет использовать порт источника этого сегмента в качестве порта назначения, но какую функцию вызывает сервер, чтобы узнать об этом порте? Это accept()
?
Ответы:
Это часть заголовка 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, чтобы увидеть пакет, и он пометит все данные для вас. Вот выделенный порт источника (обратите внимание, что он выделен в декодированном пакете, а также шестнадцатеричный дамп внизу):
источник
write
(и т.д.) отправляли в нужное место.«Запрос на подключение (
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 номер порта.TCP-сокет является потоково-ориентированным сокетом. Два дескриптора сокета (принадлежащие вам и вашему партнеру) надежно связаны. Так что вам не нужно беспокоиться о порте клиента - просто напишите свой дескриптор сокета!
Кроме того, не стесняйтесь getockname (2), если вы действительно хотите это знать (возможно, для регистрации).
источник
Соединение определяется кортежем (исходный IP-адрес, исходный порт, IP-адрес назначения, порт назначения). Ответы идут наоборот.
источник