■ С помощью функции bind
процесс может связать конкретный IP-адрес с сокетом. IP-адрес должен соответствовать одному из интерфейсов узла. Так определяется IP-адрес, который будет использоваться для отправляемых через сокет IP-дейтаграмм. При этом для сервера TCP на сокет накладывается ограничение: он может принимать только такие входящие соединения клиента, которые предназначены именно для этого IP-адреса.
Обычно клиент TCP не связывает IP-адрес с сокетом при помощи функции bind
. Ядро выбирает IP-адрес отправителя в момент подключения клиента к сокету, основываясь на используемом исходящем интерфейсе, который, в свою очередь, зависит от маршрута, требуемого для обращения к серверу [128, с. 737].
Если сервер TCP не связывает IP-адрес с сокетом, ядро назначает ему IP-адрес (указываемый в исходящих пакетах), который совпадает с адресом получателя сегмента SYN клиента [128, с. 943].
Как мы уже говорили, вызов функции bind
позволяет нам задать IP-адрес и порт (вместе или по отдельности) либо не задавать никаких аргументов. В табл. 4.5 приведены все возможные значения, которые присваиваются аргументам sin_addr
и sin_port
либо sin6_addr
и sin6_port
в зависимости от желаемого результата.
Таблица 4.5. Результаты задания IP-адреса и (или) номера порта в функции bind
Процесс задает |
Результат |
IP-адрес |
Порт |
Универсальный |
0 |
Ядро выбирает IP-адрес и порт |
Универсальный |
Ненулевое значение |
Ядро выбирает IP-адрес, процесс задает порт |
Локальный |
0 |
Процесс задает IP-адрес, ядро выбирает порт |
Локальный |
Ненулевое значение |
Процесс задает IP-адрес и порт |
Если мы зададим нулевой номер порта, то при вызове функции bind
ядро выберет динамически назначаемый порт. Но если мы зададим IP-адрес с помощью символов подстановки, ядро не выберет локальный IP-адрес, пока к сокету не присоединится клиент (TCP) либо на сокет не будет отправлена дейтаграмма (UDP).
В случае IPv4 универсальный адрес, состоящий из символов подстановки (wildcard), задается константой INADDR_ANY
, значение которой обычно нулевое. Это указывает ядру на необходимость выбора IP-адреса. Пример вы видели в листинге 1.5:
struct sockaddr_in servaddr;
servaddr sin_addr s_addr = htonl(INADDR_ANY); /* универсальный */
Этот прием работает с IPv4, где IP-адрес является 32-разрядным значением, которое можно представить как простую численную константу (в данном случае 0), но воспользоваться им при работе с IPv6 мы не можем, поскольку 128-разрядный адрес IPv6 хранится в структуре. (В языке С мы не можем поместить структуру в правой части оператора присваивания.) Эта проблема решается следующим образом:
struct sockaddr_in6 serv;
serv sin6_addr = in6addr_any; /* универсальный */
Система выделяет место в памяти и инициализирует переменную in6addr_any
, присваивая ей значение константы IN6ADDR_ANY_INIT
. Объявление внешней константы in6addr_any
содержится в заголовочном файле .
Значение INADDR_ANY
(0) не зависит от порядка байтов, поэтому использование функции htonl
в действительности не требуется. Но поскольку все константы INADDR_
, определенные в заголовочном файле , задаются в порядке байтов узла, с любой из этих констант следует использовать функцию htonl
.
Если мы поручаем ядру выбрать для нашего сокета номер динамически назначаемого порта, то функция bind
не возвращает выбранное значение. В самом деле, она не может возвратить это значение, поскольку второй аргумент функции bind
имеет спецификатор const
. Чтобы получить значение динамически назначаемого порта, заданного ядром, потребуется вызвать функцию getsockname
, которая возвращает локальный адрес протокола.
Типичным примером процесса, связывающего с сокетом конкретный IP-адрес, служит узел, на котором работают веб-серверы нескольких организаций (см. раздел 14.2 [112]). Прежде всего, у каждой организации есть свое собственное доменное имя, например www.organization.com
. Доменному имени каждой организации сопоставляется некоторый IP-адрес; различным организациям сопоставляются различные адреса, но обычно из одной и той же подсети. Например, если маска подсети 198.69.10, то IP-адресом первой организации может быть 198. 69.10.128, следующей — 198.69.10.129, и т.д. Все эти IP-адреса затем становятся псевдонимами, или альтернативными именами (alias), одного сетевого интерфейса (например, при использовании параметра alias
команды ifconfig
в 4.4BSD). В результате уровень IP будет принимать входящие дейтаграммы, предназначенные для любого из адресов, являющихся псевдонимами. Наконец, для каждой организации запускается по одной копии сервера HTTP, и каждая копия связывается с помощью функции bind
только с IP-адресом определенной организации.
Читать дальше
Конец ознакомительного отрывка
Купить книгу