1. Этот параметр допускает полностью дублированное связывание, но только если каждый сокет, который хочет связаться с тем же IP-адресом и портом, задает этот параметр сокета.
2. Параметр
SO_REUSEADDR
считается эквивалентным параметру
SO_REUSEPORT
, если связываемый IP-адрес является адресом многоадресной передачи [128, с. 731].
Проблема с этим параметром сокета заключается в том, что не все системы его поддерживают. В системах без поддержки этого параметра, но с поддержкой многоадресной передачи его функции выполняет параметр
SO_REUSEADDR
, допускающий полностью дублированное связывание, когда оно имеет смысл (то есть когда имеется сервер UDP, который может быть запущен много раз на одном и том же узле в одно и то же время, предполагающий получать либо широковещательные дейтаграммы, либо дейтаграммы многоадресной передачи).
Обобщить обсуждение этих параметров сокета можно с помощью следующих рекомендаций:
1. Устанавливайте параметр SO_
REUSEADDR
перед вызовом функции
bind
на всех серверах TCP.
2. При создании приложения многоадресной передачи, которое может быть запущено несколько раз на одном и том же узле в одно и то же время, устанавливайте параметр
SO_REUSEADDR
и связывайтесь с адресом многоадресной передачи, используемым в качестве локального IP-адреса.
Более подробно об этих параметрах сокета рассказывается в главе 22 [128].
Существует потенциальная проблема безопасности, связанная с использованием параметра
SO_REUSEADDR
. Если существует сокет, связанный, скажем, с универсальным адресом и портом 5555, то, задав параметр
SO_REUSEADDR
, мы можем связать этот порт с другим IP-адресом, например с основным (primary) IP-адресом узла. Любые приходящие дейтаграммы, предназначенные для порта 5555 и IP- адреса, который мы связали с нашим сокетом, доставляются на наш сокет, а не на другой сокет, связанный с универсальным адресом. Это могут быть сегменты SYN TCP или дейтаграммы UDP. (В упражнении 11.9 показано это свойство для UDP.) Для большинства известных служб, таких как HTTP, FTP и Telnet, это не составляет проблемы, поскольку все эти серверы связываются с зарезервированным портом. Следовательно, любой процесс, запущенный позже и пытающийся связаться с конкретным экземпляром этого порта (то есть пытающийся завладеть портом), требует прав привилегированного пользователя. Однако NFS (Network File System — сетевая файловая система) может вызвать проблемы, поскольку ее стандартный порт (2049) не зарезервирован.
ПРИМЕЧАНИЕ
Одна из сопутствующих проблем API сокетов в том, что установка пары сокетов выполняется с помощью двух вызовов функций (bind и connect) вместо одного. В [122] предлагается одиночная функция, разрешающая эту проблему:
int bind_connect_listen(int <i>sockfd</i>,
const struct sockaddr *<i>laddr</i>, int <i>laddrlen</i>,
const struct sockaddr *<i>faddr</i>, int <i>faddrlen</i>,
int <i>listen</i>);
Аргумент laddr задает локальный IP-адрес и локальный порт, аргумент faddr — удаленный IP-адрес и удаленный порт, аргумент listen задает клиент (0) или сервер (значение ненулевое; то же, что и аргумент backlog функции listen). В таком случае функция bind могла бы быть библиотечной функцией, вызывающей эту функцию с пустым указателем faddr и нулевым faddrlen, а функция connect — библиотечной функцией, вызывающей эту функцию с пустым указателем laddr и нулевым laddrlen. Существует несколько приложений, особенно FTP, которым необходимо задавать и локальную пару, и удаленную пару, которые могут вызывать bind_connect_listen непосредственно. При наличии подобной функции отпадает необходимость в параметре SO_REUSEADDR, в отличие от серверов UDP, которым явно необходимо допускать полностью дублированное связывание с одним и тем же IP-адресом и портом. Другое преимущество этой новой функции в том, что сервер TCP может ограничить себя обслуживанием запросов на соединения, приходящих от одного определенного IP-адреса и порта. Это определяется в RFC 793 [96], но невозможно с существующими API сокетов.
Параметр сокета SO_TYPE
Этот параметр возвращает тип сокета. Возвращаемое целое число — константа
SOCK_STREAM
или
SOCK_DGRAM
. Этот параметр обычно используется процессом, наследующим сокет при запуске.
Параметр сокета SO_USELOOPBACK
Этот параметр применяется только к маршрутизирующим сокетам (
AF_ROUTE
). По умолчанию он включен на этих сокетах (единственный из параметров
SO_<i>xxx</i>
, по умолчанию включенный). В этом случае сокет получает копию всего, что отправляется на сокет.
ПРИМЕЧАНИЕ
Другой способ отключить получение этих копий — вызвать функцию shutdown со вторым аргументом SHUT_RD.
7.6. Параметры сокетов IPv4
Эти параметры сокетов обрабатываются IPv4 и для них аргумент
level
равен
IPPROTO_IP
. Обсуждение пяти параметров сокетов многоадресной передачи мы отложим до раздела 19.5.
Параметр сокета IP_HRDINCL
Если этот параметр задан для символьного сокета IP (см. главу 28), нам следует создать наш собственный заголовок IP для всех дейтаграмм, которые мы отправляем через символьный сокет. Обычно ядро создает заголовок IP для дейтаграмм, отправляемых через символьный сокет, но существует ряд приложений (в частности,
traceroute
), создающих свой собственный заголовок IP, заменяющий значения, которые IP поместил бы в определенные поля заголовка.
Когда установлен этот параметр, мы создаем полный заголовок IP со следующими исключениями:
■ IP всегда сам вычисляет и записывает контрольную сумму заголовка IP.
■ Если мы устанавливаем поле идентификации IP в 0, ядро устанавливает это поле самостоятельно.
■ Если IP-адрес отправителя (source address) —
INADDR_ANY
, IP устанавливает его равным основному IP-адресу исходящего интерфейса.
■ Как устанавливать параметры IP, зависит от реализации. Некоторые реализации добавляют любые параметры IP, установленные с использованием параметра сокета
IP_OPTIONS
, к создаваемому нами заголовку, в то время как другие требуют, чтобы мы сами добавили в заголовок все необходимые параметры IP.
■ Некоторые поля должны располагаться в порядке байтов узла, тогда как другие — в сетевом порядке байтов. Это тоже зависит от реализации, из-за чего программы, работающие с символьными сокетами с параметром
IP_HDRINCL
, становятся не такими переносимыми, как хотелось бы.
Пример использования этого параметра показан в разделе 29.7. Дополнительная информация об этом параметре представлена в [128, с. 1056–1057].
Параметр сокета IP_OPTIONS
Установка этого параметра позволяет нам задавать параметры IP в заголовке IPv4. Это требует точного знания формата параметров IP в заголовке IP. Мы рассмотрим этот параметр в контексте маршрутизации от отправителя IPv4 в разделе 27.3.