Мы получаем сообщение об ошибке только по истечении времени выполнения функции connect
(которое, как мы говорили, для Solaris 9 составляет 3 мин). Обратите внимание, что наша функция err_sys
выдает текстовое сообщение, соответствующее коду ошибки ETIMEDOUT
.
В следующем примере мы пытаемся обратиться к локальному маршрутизатору, на котором не запущен сервер времени и даты:
solaris % daytimetcpcli 192.168.1.5
connect error: Connection refused
Сервер отвечает немедленно, отправляя сегмент RST.
В последнем примере мы пытаемся обратиться к недоступному адресу из сети Интернет. Просмотрев пакеты с помощью программы tcpdump
, мы увидим, что маршрутизатор, находящийся на расстоянии шести прыжков от нас, возвращает сообщение ICMP о недоступности узла:
solaris % daytimetcpcli 192.3.4.5
connect error: No route to host
Как и в случае ошибки ETIMEDOUT
, в этом примере функция connect
возвращает ошибку EHOSTUNREACH
только после ожидания в течение определенного времени.
В терминах диаграммы перехода состояний TCP (см. рис. 2.4) функция connect
переходит из состояния CLOSED
(состояния, в котором сокет начинает работать при создании с помощью функции socket
) в состояние SYN_SENT
, а затем, при успешном выполнении, в состояние ESTABLISHED
. Если выполнение функции connect
окажется неудачным, сокет больше не используется и должен быть закрыт. Мы не можем снова вызвать функцию connect
для сокета. В листинге 11.4 вы увидите, что если функция connect
выполняется в цикле, проверяя каждый IP-адрес данного узла, пока он не заработает, то каждый раз, когда выполнение функции оказывается неудачным, мы должны закрыть дескриптор сокета с помощью функции close
и снова вызвать функцию socket
.
4.4. Функция bind
Функция bind
связывает сокет с локальным адресом протокола. В случае протоколов Интернета адрес протокола — это комбинация 32-разрядного адреса IPv4 или 128-разрядного адреса IPv6 с 16-разрядным номером порта TCP или UDP.
#include
int bind(int
В руководстве при описании функции bind говорилось: «функция bind присваивает имя неименованному сокету». Использование термина «имя» спорно, обычно оно вызывает ассоциацию с доменными именами (см. главу 11), такими как foo.bar.com. Функция bind не имеет ничего общего с именами. Она задает сокету адрес протокола, а что означает этот адрес — зависит от самого протокола.
Вторым аргументом является указатель на специфичный для протокола адрес, а третий аргумент — это размер структуры адреса. В случае TCP вызов функции bind
позволяет нам задать номер порта или IP-адрес, а также задать оба эти параметра или вообще не указывать ничего.
■ Серверы связываются со своим заранее известным портом при запуске. Мы видели это в листинге 1.5. Если клиент или сервер TCP не делает этого, ядро выбирает динамически назначаемый порт для сокета либо при вызове функции connect
, либо при вызове функции listen
. Клиент TCP обычно позволяет ядру выбирать динамически назначаемый порт, если приложение не требует зарезервированного порта (см. рис. 2.10), но сервер TCP достаточно редко предоставляет ядру право выбора, так как обращение к серверам производится через заранее известные порты.