Чтение онлайн

ЖАНРЫ

UNIX: разработка сетевых приложений
Шрифт:

17 bind_req.msg_hdr.ADDR_length = addrlen;

18 bind_req.msg_hdr.ADDR_offset = sizeof(struct T_bind_req);

19 bind_req.msg_hdr.CONIND_number = 0;

20 memcpy(bind_req.addr, addr, addrlen); /* sockaddr_in{} */

21 ctlbuf.len = sizeof(struct T_bind_req) + addrlen;

22 ctlbuf.buf = (char*)&bind_req;

23 Putmsg(fd, &ctlbuf, NULL, 0);

24 ctlbuf.maxlen = sizeof(bind_ack);

25 ctlbuf.len = 0;

26 ctlbuf.buf = (char*)&bind_ack;

27 flags = RS_HIPRI;

28 Getmsg(fd, &ctlbuf, NULL, &flags);

29 if (ctlbuf.len < (int)sizeof(long))

30 err_quit("bad length from getmsg");

31 switch (bind_ack.msg_hdr.PRIM_type) {

32 case T_BIND_ACK:

33 return;

34 case T_ERROR_ACK:

35 if (ctlbuf.len < (int)sizeof(struct T_error_ack))

36 err_quit("bad length for T_ERROR_ACK");

37 error_ack = (struct T_error_ack*)&bind_ack.msg_hdr;

38 err_quit("T_ERROR_ACK from bind (%d, %d)",

39 error_ack->TLI_error, error_ack->UNIX_error);

40 default:

41 err_quit("unexpected message type: %d", bind_ack.msg_hdr.PRlM_type);

42 }

43 }

Заполнение
структуры T_bind_req

16-20
Заголовочный файл
<sys/tihdr.h>
определяет структуру
T_bind_req
:

struct T_bind_req {

long PRIM_type; /* T_BIND_REQ */

long ADDR_length; /* длина адреса */

long ADDR_offset; /* смещение адреса */

unsigned long CONIND_number; /* сообщения о соединении */

/* далее следует адрес протокола для связывания */

};

Все запросы TPI определяются как структуры, начинающиеся с поля типа

long
. Мы определяем свою собственную структуру
bind_req
, начинающуюся со структуры
T_bind_req
, после которой располагается буфер, содержащий локальный адрес для связывания. TPI ничего не говорит о содержимом буфера — оно определяется поставщиком. Поставщик TCP предполагает, что этот буфер содержит структуру
sockaddr_in
.

Мы заполняем структуру

T_bind_req
, устанавливая элемент
ADDR
_length равным размеру адреса (16 байт для структуры адреса сокета Интернета), а элемент
ADDR_offset
— равным байтовому сдвигу адреса (он следует непосредственно за структурой
T_bind_req
). У нас нет гарантии, что это местоположение соответствующим образом выровнено для записи структуры
sockaddr_in
, поэтому мы вызываем
функцию
memcpy
, чтобы скопировать структуру вызывающего процесса в нашу структуру
bind_req
. Мы присваиваем элементу
CONIND_number
нулевое значение, потому что мы находимся на стороне клиента, а не на стороне сервера.

Вызов функции putmsg

21-23
TPI требует, чтобы только что созданная нами структура была передана поставщику как одно сообщение
M_PROTO
. Следовательно, мы вызываем функцию
putmsg
, задавая структуру
bind_req
в качестве управляющей информации, без каких-либо данных и с флагом 0.

Вызов функции 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 байта).

Поделиться с друзьями: