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

ЖАНРЫ

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

Мы можем обойти как XTI, так и сокеты, и использовать непосредственно TPI. В этом разделе мы заново перепишем код нашего простого клиента времени и даты с использованием TPI вместо сокетов (сокетная версия представлена в листинге 1.1). Если провести аналогию с языками программирования, то использование XTI или сокетов можно сравнить с программированием на языках высокого уровня, таких как С или Pascal, а непосредственно TPI — с программированием на ассемблере. Мы не являемся сторонниками непосредственного использования TPI в реальной жизни. Но понимание того, как работает TPI, и написание примера с использованием этого протокола позволит нам глубже понять, как работает библиотека сокетов в потоковой

среде.

В листинге 31.1 [1] показан наш заголовочный файл

tpi_daytime.h
.

Листинг 31.1. Наш заголовочный файл tpi_daytime.h

//streams/tpi_daytime.h

1 #include "unpxti.h"

2 #include <sys/stream.h>

3 #include <sys/tihdr.h>

4 void tpi_bind(int, const void*, size_t);

5 void tpi_connect(int, const void*, size_t);

1

Все исходные коды программ, опубликованные в этой книге, вы можете найти по адресу http://www.piter.com.

6 ssize_t tpi_read(int, void*, size_t);

7 void tpi_close(int);

Нам нужно включить еще один дополнительный заголовочный файл помимо

<sys/tihdr.h>
, содержащего определения структур для всех сообщений TPI.

Листинг 31.2. Функция main для нашего клиента времени и даты с использованием TPI

//streams/tpi_daytime.c

1 #include "tpi_daytime.h"

2 int

3 main(int argc, char **argv)

4 {

5 int fd, n;

6 char recvline[MAXLINE + 1];

7 struct sockaddr_in myaddr, servaddr;

8 if (argc != 2)

9 err_quit("usage: tpi_daytime <Ipaddress>");

10 fd = Open(XTI_TCP, O_RDWR, 0);

11 /* связываем произвольный локальный адрес */

12 bzero(&myaddr, sizeof(myaddr));

13 myaddr.sin_family = AF_INET;

14 myaddr.sin_addr.s_addr = htonl(INADDR_ANY);

15 myaddr.sin_port = htons(0);

16 tpi_bind(fd, &myaddr, sizeof(struct sockaddr_in));

17 /* заполняем адрес сервера */

18 bzero(&servaddr, sizeof(servaddr));

19 servaddr.sin_family = AF_INET;

20 servaddr.sin_port = htons(13); /* сервер времени и даты */

21 Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);

22 tpi_connect(fd, &servaddr, sizeof(struct sockaddr_in));

23 for (;;) {

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: связывание локального адреса с точкой доступа

//streams/tpi_bind.c

1 #include "tpi_daytime.h"

2 void

3 tpi_bind(int fd, const void *addr, size_t addrlen)

4 {

5 struct {

6 struct T_bind_req msg_hdr;

7 char addr[128];

8 } bind_req;

9 struct {

10 struct T_bind_ack msg_hdr;

11 char addr[128];

12 } bind_ack;

13 struct strbuf ctlbuf;

14 struct T_error_ack *error_ack;

15 int flags;

16 bind_req.msg_hdr.PRIM_type = T_BIND_REQ;

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