Мы можем обойти как XTI, так и сокеты, и использовать непосредственно TPI. В этом разделе мы заново перепишем код нашего простого клиента времени и даты с использованием TPI вместо сокетов (сокетная версия представлена в листинге 1.1). Если провести аналогию с языками программирования, то использование XTI или сокетов можно сравнить с программированием на языках высокого уровня, таких как С или Pascal, а непосредственно TPI — с программированием на ассемблере. Мы не являемся сторонниками непосредственного использования TPI в реальной жизни. Но понимание того, как работает TPI, и написание примера с использованием этого протокола позволит нам глубже понять, как работает библиотека сокетов в потоковой
24 if ((n = tpi_read(fd, recvline, MAXLINE)) <= 0) {
25 if (n == 0)
26 break;
27 else
28 err_sys("tpi_read error");
29 }
30 recvline[n] = 0; /*
завершающий нуль */
31 fputs(recvline, stdout);
32 }
33 tpi_close(fd);
34 exit(0);
35 }
Открытие транспортного устройства, связывание локального адреса
10-16
Мы открываем устройство, соответствующее поставщику транспортных служб (обычно
/dev/tcp
). Мы заполняем структуру адреса сокета Интернета значениями
INADDR_ANY
и 0 (для порта), указывая тем самым TCP связать произвольный локальный адрес с нашей точкой доступа. Мы вызываем свою собственную функцию
tpi_bind
(которая будет приведена чуть ниже) для выполнения этого связывания.
Заполнение структуры адреса сервера, установление соединения
17-22
Мы заполняем другую структуру адреса сокета Интернета, внося в нее IP-адрес сервера (из командной строки) и порт (13). Мы вызываем нашу функцию
tpi_connect
для установления соединения.
Считывание данных с сервера, копирование в стандартный поток вывода
23-33
Как и в случае других клиентов времени и даты, мы просто копируем данные, пришедшие по соединению, в стандартный поток вывода, останавливаясь при получении признака конца файла, присланного сервером (например, сегмент FIN). Мы сделали этот цикл похожим на тот, который использовался в коде сокетного клиента (см. листинг 1.1), поскольку наша функция
tpi_read
при нормальном завершении соединения на стороне сервера будет возвращать нулевое значение. Затем мы вызываем нашу функцию
tpi_close
для того, чтобы закрыть эту точку доступа.
Наша функция
tpi_bind
показана в листинге 31.3.
Листинг 31.3. Функция tpi_bind: связывание локального адреса с точкой доступа