unsigned long CONIND_number; /* индекс подключения для помещения
в очередь */
};
/*
затем следует связанный адрес */
struct T_error_ack {
long PRIM_type; /* T_ERROR_ACK */
long ERROR_prim; /* примитивная ошибка ввода */
long TLI_error; /* код ошибки TLI */
long UNIX_error; /* код ошибки UNIX */
};
В начале каждого сообщения указан его тип, так что мы можем начать считывать ответ, предполагая, что это сообщение
T_BIND_ACK
, а затем, прочитав его тип, обрабатывать его тем или иным способом. Мы не ждем никаких данных от поставщика, поэтому третий аргумент функции
getmsg
мы задаем как пустой указатель.
ПРИМЕЧАНИЕ
Когда мы проверяем, соответствует ли количество возвращенной управляющей информации по меньшей мере размеру длинного целого, нужно проявить осторожность, преобразуя значение sizeof в целое число. Оператор sizeof возвращает целое число без знака, но существует вероятность того, что значение возвращенного поля len будет -1. Поскольку при выполнении операции сравнения слева располагается значение со знаком, а справа — без знака, компилятор преобразует значение со знаком в значение без знака. Если рассматривать -1 как целое без знака в архитектуре с дополнением до 2, это число получается очень большим, то есть -1 оказывается больше 4 (если предположить, что длинное целое число занимает 4 байта).
Обработка ответа
31-33
Если ответ — это сообщение
T_BIND_ACK
, то связывание прошло успешно, и мы возвращаемся. Фактический адрес, связанный с точкой доступа, возвращается в элементе
addr
нашей структуры
bind_ack
, которую мы игнорируем.
34-39
Если ответ — это сообщение
T_ERROR_ACK
, мы проверяем, было ли сообщение получено целиком, и выводим три значения, содержащиеся в возвращенной структуре. В этой простой программе при возникновении ошибки мы просто прекращаем выполнение и ничего не возвращаем вызывающему процессу.
Чтобы увидеть ошибки, которые могут возникнуть в результате запроса на связывание, мы слегка изменим нашу функцию
main
и попробуем связать какой- либо порт, отличный от 0. Например, если мы попробуем связать порт 1 (что требует прав привилегированного пользователя, так как это порт с номером меньше 1024), мы получим следующий результат:
solaris % tpi_daytime 127.0.0.1
T_ERROR_ACK from bind (3, 0)
В этой системе значение константы
EACCESS
равно 3. Если мы поменяем номер порта, задав значение большее 1023, но используемое в настоящий момент другой точкой доступа TCP, мы получим:
solaris % tpi_daytime 127.0.0.1
T_ERROR_ACK from bind (23, 0)
В данной системе значение константы
EADDRBUSY
равно 23.
Следующая функция показана в листинге 31.4. Это функция
tpi_connect
, устанавливающая соединение с сервером.
Листинг 31.4. Функция tpi_connect: установление соединения с сервером