UNIX: разработка сетевых приложений
Вызов функции getmsg для чтения сообщений с высоким приоритетомОтветом на наш запрос24-30будет либо сообщениеT_BIND_REQ, либо сообщениеT_BIND_ACK. Сообщения, содержащие подтверждение, отправляются как сообщения с высоким приоритетом (T_ERROR_ACK), так что мы считываем их при помощи функцииM_PCPROTOс флагомgetmsg. Поскольку ответ является сообщением с высоким приоритетом, он получает преимущество перед всеми обычными сообщениями в потоке.RS_HIPRIЭти два сообщения выглядят следующим образом:
struct T_bind_ack {long PRIM_type; /* T_BIND_ACK */long ADDR_length; /* длина адреса */long ADDR_offset; /* смещение адреса */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Чтобы увидеть ошибки, которые могут возникнуть в результате запроса на связывание, мы слегка изменим нашу функцию
и попробуем связать какой- либо порт, отличный от 0. Например, если мы попробуем связать порт 1 (что требует прав привилегированного пользователя, так как это порт с номером меньше 1024), мы получим следующий результат:mainsolaris % <b>tpi_daytime 127.0.0.1</b>T_ERROR_ACK from bind (3, 0)В этой системе значение константы
равно 3. Если мы поменяем номер порта, задав значение большее 1023, но используемое в настоящий момент другой точкой доступа TCP, мы получим:EACCESSsolaris % <b>tpi_daytime 127.0.0.1</b>T_ERROR_ACK from bind (23, 0)В данной системе значение константы
равно 23.EADDRBUSYСледующая функция показана в листинге 31.4. Это функция
, устанавливающая соединение с сервером.tpi_connectЛистинг 31.4. Функция tpi_connect: установление соединения с сервером
//streams/tpi_connect.c1 #include "tpi_daytime.h"2 void3 tpi_connect(int fd, const void *addr, size_t addrlen)4 {5 struct {6 struct T_conn_req msg_hdr;7 char addr[128];8 } conn_req;9 struct {10 struct l_conn_con msg_hdr;11 char addr[128];12 } conn_con;13 struct strbuf ctlbuf;14 union T_primitives rcvbuf;15 struct T_error_ack *error_ack;16 struct T_discon_ind *discon_ind;17 int flags;18 conn_req.msg_hdr.PRIM_type = T_CONN_REQ;19 conn_req.msg_hdr.DEST_length = addrlen;20 conn_req.msg_hdr.DEST_offset = sizeof(struct T_conn_req);21 conn_req.msg_hdr.OPT_length = 0;22 conn_req.msg_hdr.OPT_offset = 0;23 memcpy(conn_req.addr, addr, addrlen); /* sockaddr_in{} */24 ctlbuf.len = sizeof(struct T_conn_req) + addrlen;25 ctlbuf.buf = (char*)&conn_req;26 Putmsg(fd, &ctlbuf, NULL, 0);27 ctlbuf.maxlen = sizeof(union T_primitives);28 ctlbuf.len = 0;29 ctlbuf.buf = (char*)&rcvbuf;30 flags = RS_HIPRI;31 Getmsg(fd, &ctlbuf, NULL, &flags);32 if (ctlbuf.len < (int)sizeof(long))