Мы получаем сообщение об ошибке только по истечении времени выполнения функции
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 достаточно редко предоставляет ядру право выбора, так как обращение к серверам производится через заранее известные порты.