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)
18 return (datbuf.len);
19 else if (rcvbuf.type == T_ORDREL_IND)
20 return (0);
21 else
22 err_quit("tpi_read: unexpected type %d", rcvbuf.type);
23 } else if (ctlbuf.len == -1)
24 return (datbuf.len);
25 else
26 err_quit("tpi_read: bad length from getmsg");
27 }
9-26
На этот раз мы вызываем функцию getmsg
для считывания как данных, так и управляющей информации. Структура strbuf
, предназначенная для данных, указывает на буфер вызывающего процесса. В потоке события могут развиваться по четырем различным сценариям.
■ Данные могут прибыть в виде сообщения M_DATA
, и указанием на это является возвращенное значение длины управляющей информации, равное -1. Данные скопированы в буфер вызывающего процесса функцией getmsg
, и функция просто возвращает длину этих данных.
■ Данные могут прибыть как сообщение T_DATA_IND
, в этом случае управляющая информация будет содержаться в структуре T_data_ind
:
struct T_data_ind {
long PRIM_type; /* T_DATA_IND */
long MORE_flag; /* еще данные */
};
Если возвращено такое сообщение, мы игнорируем поле MORE_flag
(оно вообще не задается для таких протоколов, как TCP) и просто возвращаем длину данных, скопированных в буфер вызывающего процесса функцией getmsg
.
Вильям Л Саймон , Вильям Саймон , Наталья Владимировна Макеева , Нора Робертс , Юрий Викторович Щербатых
Зарубежная компьютерная, околокомпьютерная литература / ОС и Сети, интернет / Короткие любовные романы / Психология / Прочая справочная литература / Образование и наука / Книги по IT / Словари и Энциклопедии