Как могут существовать неисключительные порты, когда tcp идентифицирует приложения, используя 16-битный номер порта? - PullRequest
1 голос
/ 17 апреля 2011

Я не могу придумать точный API сокета, но я помню, что есть опция сокета, которая демонстрирует порт эксклюзивный / не эксклюзивный.

Если это не исключение, как TCP может знать, в какое приложение оно должно перенаправлять данные для определенного порта назначения?

Ответы [ 2 ]

5 голосов
/ 17 апреля 2011

Я думаю, что вы можете ссылаться на опцию SO_REUSEPORT, доступную в некоторых системах.

На странице справки BSD:

SO_REUSEPORT позволяет полностью дублировать привязки несколькими процессами, есливсе они устанавливают SO_REUSEPORT перед привязкой порта.Эта опция позволяет нескольким экземплярам программы получать каждый UDP / IP многоадресные или широковещательные дейтаграммы, предназначенные для связанного порта.

Реализации для этого сильно различаются (от несуществующих до ограниченных UDP,разрешить TCP также).В случаях, когда разрешен TCP, соединения различаются по парам source и target (ip, port).Этого достаточно, чтобы реализация могла решить, какому приложению нужен какой пакет.(см., например, Trek - опции сокетов .)

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

  • входящие пакеты, которые инициируют (SYN) соединение, направляются в единственный принимающий сокет
  • входящие пакеты для подключенного потока маршрутизируютсяк сокету они принадлежат

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


Вот как это может работать.Добровольно упрощение ПТС (без трехстороннего рукопожатия).Давайте отметим информацию о сокете, хранящуюся в стеке TCP следующим образом:

(socketname)[owner app, (local IP, local port), (state, remote IP, remote port)]

. Итак, давайте настроим три приложения A, B и C:

App A -> bind (localhost,12345,SO_REUSEPORT)
    TCP stack: create socket (s1)[belongs to A, (localhost,12345), (not connected)]
App A <- s1

App B -> bind (localhost,12345,SO_REUSEPORT)
    TCP stack: create socket (s2)[belongs to B, (localhost,12345), (not connected)]
App B <- s2

App C -> bind (localhost,12345,SO_REUSEPORT)
    TCP stack: create socket (s3)[belongs to C, (localhost,12345), (not connected)]
App C <- s3
App C -> s3.listen()
    TCP stack: update socket (s3)[belongs to C, (localhost,12345), (open for business)]
App C -> s3.accept()

. На данный момент нет данных.был отправлен, но ядро ​​точно знает, какой сокет принадлежит какому приложению.Давайте на самом деле попробуем сделать что-то со своим сокетом:

App A -> s1.connect(otherhost,54321)
    TCP stack: update socket (s1)[belongs to A, (localhost,12345), (connecting, otherhost,54321)]
    TCP stack: send SYN

Здесь могут произойти три вещи:

входящий ACK-пакет от (otherhost, 54321) с правильной последовательностью:это нормально, это для s1, другой возможности нет
    TCP stack: update socket (s1)[belongs to A, (localhost,12345), (connected,otherhost,54321)]
    TCP stack: send SYN/ACK
    TCP stack: notify App A that socket is connected
App A <- connect succeeded, you can start doin' stuff

входящий пакет SYN от (client, 4343): может быть только для s3, только сокет готов к SYN
    TCP stack: create new socket (s4)[belongs to C, (localhost,12345), (connected,client,4343)]
    TCP stack: send ACK to client
    TCP stack: notify App C that (s4) has been accepted
App C <- s4 returned from accept()

входящий пакет откуда-то еще:
    TCP stack: drop or reject, there are no matching sessions

Давайте представим, что две вещи произошли выше.Информация о ядре теперь:

(s1)[belongs to A, (localhost,12345), (connected,otherhost,54321)]
(s2)[belongs to B, (localhost,12345), (not connected)]
(s3)[belongs to C, (localhost,12345), (open for business)]
(s4)[belongs to C, (localhost,12345), (connected,client,4343)]

Теперь могут входить четыре вида пакетов:

входящий нормальный пакет от (otherhost, 54321): соответствует s1, передать егов приложение A входящий нормальный пакет от (client, 4343): соответствует s4, передает его приложению C входящий пакет SYN от (otherclient, 2398): соответствует s3, как и раньше что угодноиначе: отбросить или отклонить, недопустимое состояние

Стек TCP всегда определяет, к какому сокету принадлежит пакет.Таким образом, он знает, куда доставлять данные.


SO_REUSEADDR отличается: он позволяет привязывать только порт в состоянии TIME_WAIT - т.е. порт уже закрывается, сокет, который имелоткрыт он уже выдан close (более или менее, есть другие условия).При SO_REUSEADDR только одна розетка за раз удерживает розетку открытой.

0 голосов
/ 17 апреля 2011

Сокет идентифицируется по IP-адресу и порту - оба. Вместе в API сокетов BSD они называются «имя». Вы можете привязать свой сокет к имени и, если это имя содержит определенный адрес, вы можете привязать другой сокет к другому имени с тем же портом.

Также: соединение - это пара из двух сокетов, поэтому одну пару адрес / порт можно использовать в нескольких соединениях - это означает, что более одного подключенного сокета может иметь одно и то же имя (но не тот же FD).

...