Вход/Регистрация
UNIX: разработка сетевых приложений
вернуться

Стивенс Уильям Ричард

Шрифт:

Вторым аргументом является указатель на специфичный для протокола адрес, а третий аргумент — это размер структуры адреса. В случае 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
.

  • Читать дальше
  • 1
  • ...
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: