Книга: 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
. Вскоре мы увидим, как использовать это обстоятельство и сделать с каналами что-то интересное.
- 11.4.1. Создание входных точек устройств и именованных каналов
- 9.3.1.2. Буферирование каналов
- Использование именованных каналов
- Создание именованных каналов
- Подключение клиентов именованных каналов
- Функции состояния именованных каналов
- Создание, подключение и именование каналов и почтовых ящиков
- Сравнение серверов именованных каналов и сокетов
- 5.4.1. Создание каналов
- 11.6. Создание неименованных каналов
- Пример A-17. fifo: Создание резервных копий с помощью именованных каналов
- 2.3. Создание и открытие каналов IPC