4.4. Функция bind

4.4. Функция bind

Функция bind связывает сокет с локальным адресом протокола. В случае протоколов Интернета адрес протокола — это комбинация 32-разрядного адреса IPv4 или 128-разрядного адреса IPv6 с 16-разрядным номером порта TCP или UDP.

#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);

Возвращает: 0 в случае успешного выполнения, -1 в случае ошибки

ПРИМЕЧАНИЕ

В руководстве при описании функции bind говорилось: «функция bind присваивает имя неименованному сокету». Использование термина «имя» спорно, обычно оно вызывает ассоциацию с доменными именами (см. главу 11), такими как foo.bar.com. Функция bind не имеет ничего общего с именами. Она задает сокету адрес протокола, а что означает этот адрес — зависит от самого протокола.

Вторым аргументом является указатель на специфичный для протокола адрес, а третий аргумент — это размер структуры адреса. В случае TCP вызов функции bind позволяет нам задать номер порта или IP-адрес, а также задать оба эти параметра или вообще не указывать ничего.

? Серверы связываются со своим заранее известным портом при запуске. Мы видели это в листинге 1.5. Если клиент или сервер TCP не делает этого, ядро выбирает динамически назначаемый порт для сокета либо при вызове функции connect, либо при вызове функции listen. Клиент TCP обычно позволяет ядру выбирать динамически назначаемый порт, если приложение не требует зарезервированного порта (см. рис. 2.10), но сервер TCP достаточно редко предоставляет ядру право выбора, так как обращение к серверам производится через заранее известные порты.

ПРИМЕЧАНИЕ

Исключением из этого правила являются серверы удаленного вызова процедур RPC (Remote Procedure Call). Обычно они позволяют ядру выбирать динамически назначаемый порт для их прослушиваемого сокета, поскольку затем этот порт регистрируется программой отображения портов RPC. Клиенты должны соединиться с этой программой, чтобы получить номер динамически назначаемого порта до того, как они смогут соединиться с сервером с помощью функции connect. Это также относится к серверам RPC, использующим протокол UDP.

? С помощью функции 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 содержится в заголовочном файле <netinet/in.h>.

Значение INADDR_ANY (0) не зависит от порядка байтов, поэтому использование функции htonl в действительности не требуется. Но поскольку все константы INADDR_, определенные в заголовочном файле <netinet/in.h>, задаются в порядке байтов узла, с любой из этих констант следует использовать функцию 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-адресом определенной организации.

ПРИМЕЧАНИЕ

В качестве альтернативы можно запустить одиночный сервер, связанный с универсальным адресом. Когда происходит соединение, сервер вызывает функцию getsockname, чтобы получить от клиента IP-адрес получателя, который (см. наше обсуждение ранее) может быть равен 198.69.10.128,198.69.10.129 и т.д. Затем сервер обрабатывает запрос клиента па основе именно того IP-адреса, к которому было направлено это соединение.

Одним из преимуществ связывания с конкретным IP-адресом является то, что демультиплексирование данного IP-адреса с процессом сервера выполняется ядром.

Следует внимательно относиться к различию интерфейса, на который приходит пакет, и IP-адреса получателя этого пакета. В разделе 8.8 мы поговорим о моделях систем с гибкой привязкой (weak end system) и с жесткой привязкой (strong end system). Большинство реализаций используют первую модель, то есть считают обычным явлением принятие пакета на интерфейсе, отличном от указанного в IP-адресе получателя. (При этом подразумевается узел с несколькими сетевыми интерфейсами.) При связывании с сокетом конкретного IP-адреса на этом сокете будут приниматься дейтаграммы с заданным IP-адресом получателя, и только они. Никаких ограничений на принимающий интерфейс не накладывается — эти ограничения возникают только в случае, если используется модель системы с жесткой привязкой.

Общей ошибкой выполнения функции bind является EADDRINUSE, указывающая на то, что адрес уже используется. Более подробно мы поговорим об этом в разделе 7.5, когда будем рассматривать параметры сокетов SO_REUSEADDR и SO_REUSEPORT.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

Функция SUM

Из книги Обработка баз данных на Visual Basic®.NET автора Мак-Манус Джеффри П

Функция SUM Ваши возможности в подведении итогов не ограничены простым подсчетом записей. Используя функцию SUM, можно генерировать итоговые результаты для всех возвращаемых записей по любым числовым полям. Например, для создания запроса, который генерирует итоги по


Функция uni()

Из книги Fiction Book Designer Краткое руководство автора Автор неизвестен

Функция uni() Поиск/замена символа по его юникодному номеру также может быть сделана при помощи функции uni().Пример функции uni(): Boouni(107,32)Designer найдет слово Book


Функция uni()

Из книги Fiction Book Designer 3.2. Краткое руководство автора Izekbis

Функция uni() Поиск/замена символа по его юникодному номеру также может быть сделана при помощи функции uni().Пример функции uni(): Boouni(107,32)Designer найдет слово Book


Функция pthread_rwlock_wrlock

Из книги UNIX: взаимодействие процессов автора Стивенс Уильям Ричард

Функция pthread_rwlock_wrlock Текст функции pthread_rwlock_wrlock приведен в листинге 8.6.11-17 Если ресурс заблокирован на считывание или запись (значение rw_refcount отлично от 0), мы приостанавливаем выполнение потока. Для этого мы увеличиваем rw_nwaitwriters и вызываем pthread_cond_wait с условной переменной


12.3 Программное обеспечение BIND

Из книги TCP/IP Архитектура, протоколы, реализация (включая IP версии 6 и IP Security) автора Фейт Сидни М

12.3 Программное обеспечение BIND Многие разработчики компьютеров предоставляют бесплатное программное обеспечение для сервера имен. Обычно оно является адаптацией пакета Berkeley Internet Domain (BIND) для конкретных условий. Периодически в Интернете появляются новые бесплатные


Главный конфигурационный файл BIND

Из книги Сетевые средства Linux автора Смит Родерик В.

Главный конфигурационный файл BIND Основные опции BIND задаются в главном конфигурационном файле с именем named.conf. Этот файл обычно располагается в каталоге /etc. В некоторых дистрибутивных пакетах Linux файл с опциями, установленными по умолчанию, в каталоге /etc отсутствует. В


Запуск сервера BIND в рамках поддерева chroot

Из книги Технология XSLT автора Валиков Алексей Николаевич

Запуск сервера BIND в рамках поддерева chroot Ранее описывался процесс подготовки сервера к запуску в рамках поддерева chroot. Чтобы лучше понять изложенный выше материал, желательно рассмотреть запуск конкретного сервера в подобном режиме. В качестве примера выберем сервер


Функция not

Из книги PGP: Кодирование и шифрование информации с открытым ключом. автора Левин Максим


Функция sum

Из книги Fiction Book Designer 3.2. Руководство по созданию книг автора


Функция contains

Из книги Введение в криптографию автора Циммерманн Филипп


Функция id

Из книги UNIX: разработка сетевых приложений автора Стивенс Уильям Ричард


Хэш-функция.

Из книги автора

Хэш-функция. Еще одно важное преимущество использования PGP состоит в том, что PGP применяет так называемую «хэш-функцию», которая действует таким образом, что в том случае какого-либо изменения информации, пусть даже на один бит, результат «хэш-функции» будет совершенно


Функция uni()

Из книги автора

Функция uni() Поиск/замена символа по его юникодному номеру также может быть сделана при помощи функции uni().Пример функции uni(): Boouni(107,32)Designer найдет слово Book


Хэш-функция

Из книги автора

Хэш-функция Однако описанная выше схема имеет ряд существенных недостатков. Она крайне медлительна и производит слишком большой объём данных — по меньшей мере вдвое больше объёма исходной информации. Улучшением такой схемы становится введение в процесс преобразования


Пример: функция bind и доменный сокет Unix

Из книги автора

Пример: функция bind и доменный сокет Unix Программа, показанная в листинге 15.2, создает доменный сокет Unix, с помощью функции bind связывает с ним полное имя и затем вызывает функцию getsockname и выводит это полное имя.Листинг 15.2. Связывание полного имени с доменным сокетом