TCP не дает нам возможности запустить множество серверов, которые с помощью функции bind
связываются с одним и тем же IP-адресом и одним и тем же портом: это случай полностью дублированного связывания ( completely duplicate binding ). То есть мы не можем запустить один сервер, связывающийся с адресом 198.69.10.2 и портом 80, и другой сервер, также связывающийся с адресом 198.69.10.2 и портом 80, даже если для второго сервера мы установим параметр SO_REUSEADDR
.
По соображениям безопасности некоторые операционные системы запрещают связывать несколько серверов с адресом подстановки, то есть описанный выше сценарий не работает даже с использованием параметра SO_REUSEADDR
. В такой системе сервер, связываемый с адресом подстановки, должен запускаться последним. Таким образом предотвращается привязка сервера злоумышленника к IP-адресу и порту, которые уже обрабатываются системной службой. Особенно это важно для службы NFS, которая обычно не использует выделенный порт.
3. Параметр SO_REUSEADDR
позволяет одиночному процессу связывать один и тот же порт с множеством сокетов, так как при каждом связывании задается уникальный IP-адрес. Это обычное явление для серверов UDP, так как им необходимо знать IP-адрес получателя запросов клиента в системах, не поддерживающих параметр сокета IP_RECVSTADDR
. Эта технология обычно не применяется с серверами TCP, поскольку сервер TCP всегда может определить IP-адрес получателя при помощи вызова функции getsockname
, после того как соединение установлено. Однако на многоинтерфейсном узле сервер TCP, работающий с частью адресов локального узла, мог бы воспользоваться этой функцией.
4. Параметр SO_REUSEADDR
допускает полностью дублированное связывание : связывание с помощью функции bind
с IP-адресом и портом, когда тот же IP-адрес и тот же порт уже связаны с другим сокетом. Обычно это свойство доступно только в системах с поддержкой многоадресной передачи без поддержки параметра сокета SO_REUSEPORT (который мы опишем чуть ниже), и только для сокетов UDP (многоадресная передача не работает с TCP).
Это свойство применяется при многоадресной передаче для многократного выполнения одного и того же приложения на одном и том же узле. Когда приходит дейтаграмма UDP для одного из многократно связанных сокетов, действует следующее правило: если дейтаграмма предназначена либо для широковещательного адреса, либо для адреса многоадресной передачи, то одна копия дейтаграммы доставляется каждому сокету. Но если дейтаграмма предназначена для адреса направленной передачи, то дейтаграмма доставляется только на один сокет. Какой сокет получит дейтаграмму, если в случае направленной передачи существует множество сокетов, соответствующих дейтаграмме, — зависит от реализации. На с. 777-779 [128] об этом свойстве рассказывается более подробно. О широковещательной и многоадресной передаче мы поговорим соответственно в главах 20 и 21.
В упражнениях 7.5 и 7.6 показаны примеры использования этого параметра сокета.
Вместо того чтобы перегружать параметр SO_REUSEADDR
семантикой многоадресной передачи, допускающей полностью дублированное связывание, в 4.4BSD был введен новый параметр сокета SO_REUSEPORT
, обладающий следующей семантикой:
1. Этот параметр допускает полностью дублированное связывание, но только если каждый сокет, который хочет связаться с тем же IP-адресом и портом, задает этот параметр сокета.
2. Параметр SO_REUSEADDR
считается эквивалентным параметру SO_REUSEPORT
, если связываемый IP-адрес является адресом многоадресной передачи [128, с. 731].
Проблема с этим параметром сокета заключается в том, что не все системы его поддерживают. В системах без поддержки этого параметра, но с поддержкой многоадресной передачи его функции выполняет параметр SO_REUSEADDR
, допускающий полностью дублированное связывание, когда оно имеет смысл (то есть когда имеется сервер UDP, который может быть запущен много раз на одном и том же узле в одно и то же время, предполагающий получать либо широковещательные дейтаграммы, либо дейтаграммы многоадресной передачи).
Обобщить обсуждение этих параметров сокета можно с помощью следующих рекомендаций:
1. Устанавливайте параметр SO_ REUSEADDR
перед вызовом функции bind
на всех серверах TCP.
2. При создании приложения многоадресной передачи, которое может быть запущено несколько раз на одном и том же узле в одно и то же время, устанавливайте параметр SO_REUSEADDR
и связывайтесь с адресом многоадресной передачи, используемым в качестве локального IP-адреса.
Читать дальше
Конец ознакомительного отрывка
Купить книгу