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

ЖАНРЫ

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

18-26
В TPI определена структура
T_conn_req
, содержащая адрес протокола и параметры для соединения:

struct T_conn_req {

long PRIM_type; /* T_CONN_REQ */

long DEST_length; /* длина адреса получателя */

long DEST_offset; /* смещение адреса получателя */

long OPT_length; /* длина параметров */

long OPT_offset; /*
смещение параметров */

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

};

Как и в случае функции

tpi_bind
, мы определяем свою собственную структуру с именем
conn_req
, которая включает в себя структуру
T_conn_req
, а также содержит место для адреса протокола. Мы заполняем структуру
conn_req
, обнуляя поля
OPT_length
и
OPT_offset
. Мы вызываем функцию
putmsg
только с управляющей информацией и флагом 0 для отправки сообщения типа
M_PROTO
вниз по потоку.

Чтение ответа

27-45
Мы вызываем функцию
getmsg
, ожидая получить в ответ либо сообщение
T_OK_ACK
, если было начато установление соединения, либо сообщение
T_ERROR_ACK
(которые мы уже показывали выше). В случае ошибки мы завершаем выполнение программы. Поскольку мы не знаем, сообщение какого типа мы получим, то определяем объединение с именем
T_primitives
для приема всех возможных запросов и ответов и размещаем это объединение в памяти как входной буфер для управляющей информации при вызове функции
getmsg
.

struct T_ok_ack {

long PRIM_type; /* T_OK_ACK */

long CORRECT_prim; /* корректный примитив */

};

Ожидание завершения установления соединения

46-65
Сообщение
T_OK_ACK
, полученное нами на предыдущем этапе, указывает лишь на то, что соединение успешно начало устанавливаться. Теперь нам нужно дождаться сообщения
T_CONN_CON
, указывающего на то, что другой конец соединения подтверждает получение запроса на соединение.

struct T_conn_con {

long PRIM_type; /* T_CONN_CON */

long RES_length; /* длина адреса собеседника */

long RES_offset; /* смещение адреса собеседника */

long OPT_length; /* длина параметра */

long OPT_offset; /* смещение параметра */

/* далее следуют адрес протокола и параметры собеседника */

};

Мы снова вызываем функцию

getmsg
, но ожидаемое нами сообщение посылается как сообщение типа
M_PROTO
, а не как сообщение
M_PCPROTO
, поэтому мы обнуляем флаги. Если мы получаем сообщение
T_CONN_CON
,
значит, соединение установлено, и мы возвращаемся, но если соединение не было установлено (по причине того, что процесс собеседника не запущен, истекло время ожидания или еще по какой-либо причине), то вместо этого вверх по потоку отправляется сообщение
T_DISCON_IND
:

struct T_discon_ind {

long PRIM_type; /* T_DISCON_IND */

long DISCON_reason; /* причина разрыва соединения */

long SEQ_number; /* порядковый номер */

};

Мы можем посмотреть, какие ошибки могут быть возвращены поставщиком. Сначала мы задаем IP-адрес узла, на котором не запущен сервер времени и даты:

solaris26 % tpi_daytime 192.168.1.10

tpi_connect2: T_DISCON_IND from conn (146)

Код 146 соответствует ошибке

ECONNREFUSED
. Затем мы задаем IP-адрес, который не связан с Интернетом:

solaris26 % tpi_daytime 192.3.4.5

tpi_connect2: T_DISCON_IND from conn (145)

На этот раз возвращается ошибка

ETIMEDOUT
. Но если мы снова запустим нашу программу, задавая тот же самый IP-адрес, то получим другую ошибку:

solaris26 % tpi_daytime 192.3.4.5

tpi_connect2: T_DISCON_IND from conn (148)

На этот раз мы получаем ошибку

EHOSTUNREACH
. Различие в том, что в первый раз не было возвращено сообщение ICMP о недоступности узла, а во второй раз мы получили это сообщение.

Следующая функция, которую мы рассмотрим, — это

tpi_read
, показанная в листинге 31.5. Она считывает данные из потока.

Листинг 31.5. Функция tpi_read: считывание данных из потока

//streams/tpi_read.c

1 #include "tpi_daytime.h"

2 ssize_t

3 tpi_read(int fd, void *buf, size_t len)

4 {

5 struct strbuf ctlbuf;

6 struct strbuf datbuf;

7 union T_primitives rcvbuf;

8 int flags;

9 ctlbuf maxlen = sizeof(union T_primitives);

10 ctlbuf.buf = (char*)&rcvbuf;

11 datbuf.maxlen = len;

12 datbuf.buf = buf;

13 datbuf.len = 0;

14 flags = 0;

15 Getmsg(fd, &ctlbuf, &datbuf, &flags);

16 if (ctlbuf.len >= (int)sizeof(long)) {

17 if (rcvbuf.type == T_DATA_IND)

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