Книга: Linux программирование в примерах

9.3.1.1. Создание каналов

9.3.1.1. Создание каналов

Системный вызов pipe() создает канал:

#include <unistd.h> /* POSIX */
int pipe(int filedes[2]);

Значение аргумента является адресом массива из двух элементов целого типа, pipe() возвращает 0 при успешном возвращении и -1, если была ошибка.

Если вызов был успешным, у процесса теперь есть два дополнительных открытых дескриптора файла. Значение filedes[0] является читаемым концом канала, a filedes [1] — записываемым концом. (Удобным мнемоническим способом запоминания является то, что читаемый конец использует индекс 0, аналогичный дескриптору стандартного ввода 0, а записываемый конец использует индекс 1, аналогичный дескриптору стандартного вывода 1.)

Как упоминалось, данные, записанные в записываемый конец, считываются из читаемого конца. После завершения работы с каналом оба конца закрываются с помощью вызова close(). Следующая простая программа, ch09-pipedemo.c, демонстрирует каналы путем создания канала, записи в него данных, а затем чтения этих данных из него:

1  /* ch09-pipedemo.c --- демонстрация ввода/вывода с каналом. */
2
3  #include <stdio.h>
4  #include <errno.h>
5  #include <unistd.h>
6
7  /* main --- создание канала, запись в него и чтение из него. */
8
9  int main(int argc, char **argv)
10 {
11  static const char mesg[] = "Don't Panic!"; /* известное сообщение */
12  char buf[BUFSIZ];
13  ssize_t rcount, wcount;
14  int pipefd[2];
15  size_t l;
16
17  if (pipe(pipefd) < 0) {
18   fprintf(stderr, "%s: pipe failed: %sn", argv[0],
19    strerror(errno));
20   exit(1);
21  }
22
23  printf("Read end = fd %d, write end = fd %dn",
24   pipefd[0], pipefd[1]);
25
26  l = strlen(mesg);
27  if ((wcount = write(pipefd[1], mesg, 1)) != 1) {
28   fprintf(stderr, "%s: write failed: %sn", argv[0],
29    strerror(errno));
30   exit(1);
31  }
32
33  if ((rcount = read(pipefd[0], buf, BUFSIZ)) != wcount) {
34   fprintf(stderr, "%s: read failed: %sn", argv[0],
35    strerror(errno));
36   exit(1);
37  }
38
39  buf[rcount] = '';
40
41  printf("Read <%s> from pipen", buf);
42  (void)close(pipefd[0]);
43  (void)close(pipefd[1]);
44
45  return 0;
46 }

Строки 11–15 объявляют локальные переменные; наибольший интерес представляет mesg, который представляет текст, проходящий по каналу.

Строки 17–21 создают канал с проверкой ошибок; строки 23–24 выводят значения новых дескрипторов файлов (просто для подтверждения, что они не равны 0, 1 или 2)

В строке 26 получают длину сообщения для использования с write(). Строки 27–31 записывают сообщение в канал, снова с проверкой ошибок.

Строки 33–37 считывают содержимое канала, опять с проверкой ошибок. Строка 39 предоставляет завершающий нулевой байт, так что прочитанные данные могут использоваться в качестве обычной строки. Строка 41 выводит данные, а строки 42–43 закрывают оба конца канала. Вот что происходит при запуске программы:

$ ch09-pipedemo
Read end = fd 3, write end = fd 4
Read <Don't Panic!> from pipe

Эта программа не делает ничего полезного, но она демонстрирует основы. Обратите внимание, что нет вызовов open() или creat() и что программа не использует три своих унаследованных дескриптора. Тем не менее, write() и read() завершаются успешно, показывая, что дескрипторы файлов действительны и что данные, поступающие в канал, действительно выходят из него.[95] Конечно, будь сообщение слишком большим, наша программа не работала бы. Это происходит из-за того, что размер (памяти) каналов ограничен, факт, который мы обсудим в следующем разделе.

Подобно другим дескрипторам файлов, дескрипторы для каналов наследуются порожденным процессом после fork, и если они не закрываются, все еще доступны после exec. Вскоре мы увидим, как использовать это обстоятельство и сделать с каналами что-то интересное.

Оглавление книги


Генерация: 0.330. Запросов К БД/Cache: 0 / 2
поделиться
Вверх Вниз