UNIX: разработка сетевых приложений
long DISCON_reason; /* причина разрыва соединения */long SEQ_number; /* порядковый номер */};Мы можем посмотреть, какие ошибки могут быть возвращены поставщиком. Сначала мы задаем IP-адрес узла, на котором не запущен сервер времени и даты:
solaris26 % <b>tpi_daytime 192.168.1.10</b>tpi_connect2: T_DISCON_IND from conn (146)Код 146 соответствует ошибке
. Затем мы задаем IP-адрес, который не связан с Интернетом:ECONNREFUSEDsolaris26 % <b>tpi_daytime 192.3.4.5</b>tpi_connect2: T_DISCON_IND from conn (145)На этот раз возвращается ошибка
. Но если мы снова запустим нашу программу, задавая тот же самый IP-адрес, то получим другую ошибку:ETIMEDOUTsolaris26 % <b>tpi_daytime 192.3.4.5</b>tpi_connect2: T_DISCON_IND from conn (148)На этот раз мы получаем ошибку
. Различие в том, что в первый раз не было возвращено сообщение ICMP о недоступности узла, а во второй раз мы получили это сообщение.EHOSTUNREACHСледующая функция, которую мы рассмотрим, — это
, показанная в листинге 31.5. Она считывает данные из потока.tpi_readЛистинг 31.5. Функция tpi_read: считывание данных из потока
//streams/tpi_read.c1 #include "tpi_daytime.h"2 ssize_t3 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 else22 err_quit("tpi_read: unexpected type %d", rcvbuf.type);23 } else if (ctlbuf.len == -1)24 return (datbuf.len);25 else26 err_quit("tpi_read: bad length from getmsg");27 }Считывание управляющей информации и данных, обработка ответаНа этот раз мы вызываем функцию9-26для считывания как данных, так и управляющей информации. Структураgetmsg, предназначенная для данных, указывает на буфер вызывающего процесса. В потоке события могут развиваться по четырем различным сценариям.strbuf■ Данные могут прибыть в виде сообщения
, и указанием на это является возвращенное значение длины управляющей информации, равное -1. Данные скопированы в буфер вызывающего процесса функциейM_DATA, и функция просто возвращает длину этих данных.getmsg■ Данные могут прибыть как сообщение
, в этом случае управляющая информация будет содержаться в структуреT_DATA_IND:T_data_indstruct T_data_ind {long PRIM_type; /* T_DATA_IND */long MORE_flag; /* еще данные */};Если возвращено такое сообщение, мы игнорируем поле
(оно вообще не задается для таких протоколов, как TCP) и просто возвращаем длину данных, скопированных в буфер вызывающего процесса функциейMORE_flag.getmsg■ Сообщение
возвращается, если все данные получены и следующим элементом является сегментT_ORDREL_IND:FINstruct T_ordrel_ind {long PRIM_type; /* T_ORDREL_IND */};Это нормальное завершение. Мы просто возвращаем нулевое значение, указывая вызывающему процессу, что по соединению получен признак конца файла.
■ Сообщение
возвращается, если произошел разрыв соединения. Наша последняя функция — этоT_DISCON_IND, показанная в листинге 31.6.tpi_closeЛистинг 31.6. Функция tpi_close: отправка запроса о завершении собеседнику
//streams/tpi_close.c1 #include "tpi_daytime.h"2 void3 tpi_close(int fd)4 {5 struct T_ordrel_req ordrel_req;6 struct strbuf ctlbuf;7 ordrel_req PRIM_type = T_ORDREL_REQ;8 ctlbuf.len = sizeof(struct T_ordrel_req);9 ctlbuf.buf = (char*)&ordrel_req;10 Putmsg(fd, &ctlbuf, NULL, 0);11 Close(fd);12 }Отправка запроса о завершении собеседникуМы формируем структуру7-10:T_ordrel_reqstruct T_ordrel_req {long PRIM_type; /* T_ORDREL_REQ */