Литмир - Электронная Библиотека
Содержание  
A
A

31.5. Функция ioctl

Говоря о потоках, мы снова возвращаемся к функции

ioctl
, которая уже была описана в главе 17.

#include <stropts.h>

int ioctl(int <i>fd</i>, int <i>request</i>, ... /* void *<i>arg</i> */ );

<i>Возвращает: 0 в случае успешного выполнения, -1 в случае ошибки</i>

Единственным изменением относительно прототипа функции, приведенного в разделе 17.2, является включение заголовочного файла, необходимого для работы с потоками.

Существует примерно 30 запросов (

request
), так или иначе влияющих на головной модуль потока. Каждый из запросов начинается с
I_
, и обычно документация на них приводится на странице руководства
streamio
.

31.6. TPI: интерфейс поставщика транспортных служб

На рис. 31.3 мы показали, что TPI — это интерфейс, предоставляющий доступ к транспортному уровню для расположенных выше уровней. Этот интерфейс используется в потоковой среде как сокетами, так и XTI. Из рис. 31.3 видно, что комбинация библиотеки сокетов и

sokmod
, а также комбинация библиотеки XTI и
timod
обмениваются сообщениями TPI с TCP и UDP.

TPI является интерфейсом, основанным на сообщениях (message-based). Он определяет сообщения, которыми обменивается приложение (например, XTI или библиотека сокетов) и транспортный уровень. Точнее, TPI задает формат этих сообщений и то, какое действие производит каждое из сообщений. Во многих случаях приложение посылает запрос поставщику (например, «Связать данный локальный адрес»), а поставщик посылает обратно ответ («Выполнено» или «Ошибка»). Некоторые события, происходящие асинхронно на стороне поставщика (например, прибытие запроса на соединение с сервером), инициируют отправку сигнала или сообщения вверх по потоку.

Мы можем обойти как 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 &quot;unpxti.h&quot;

 2 #include &lt;sys/stream.h&gt;

 3 #include &lt;sys/tihdr.h&gt;

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

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

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

 7 void tpi_close(int);

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

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

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

//streams/tpi_daytime.c

 1 #include &quot;tpi_daytime.h&quot;

 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(&quot;usage: tpi_daytime &lt;Ipaddress&gt;&quot;);

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

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

12  bzero(&amp;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, &amp;myaddr, sizeof(struct sockaddr_in));

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

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

19  servaddr.sin_family = AF_INET;

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

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

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

23  for (;;) {

24   if ((n = tpi_read(fd, recvline, MAXLINE)) &lt;= 0) {

25    if (n == 0)

26     break;

27    else

28    err_sys(&quot;tpi_read error&quot;);

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
(которая будет приведена чуть ниже) для выполнения этого связывания.

вернуться

1

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

361
{"b":"225366","o":1}