Главная страница  Взаимодействие нетривиальных процессов 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 [ 18 ] 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

14 WriteCwritefd. buff, len);

15 /* считывание из канала, вывод в stdout */

16 while ( (n = ReadCreadfd, buff. MAXLINE)) > 0)

17 WriteCSTDOUT FILENO, buff, n):

18 }

Считывание полного имени из стандартного потока ввода

8-14 Полное имя файла считывается из стандартного потока ввода и записывается в канал после удаления завершающего символа перевода строки, возвращаемого функцией fgets.

Копирование из канала в стандартный поток вывода

15-17 Затем клиент считывает все, что сервер направляет в канал, и записывает эти данные в стандартный поток вывода. Ожидается, что это будет содержимое файла, но в случае его отсутствия будет принято и записано в стандартный поток вывода сообщение об ошибке.

В листинге 4.3 приведена функция server.

Листинг 4.3. Функция server для приложения клиент-сервер с двумя каналами

pipe/server,с

1 #include unpipc.h

2 void

3 serverCint readfd, int writefd)

5 int fd:

6 ssize t n;

7 char buff[MAXLINE+l]:

8 /* получение полного имени из канала IPC */

9 if ( (n = ReadCreadfd. buff. MAXLINE)) == 0)

10 err quit( end-of-file while reading pathname ):

11 buff[n] = \0; /* полное имя завершается О */

12 if ( (fd = openCbuff, 0 ROONLY)) < 0) {

13 /* 4error: must tell client */

14 snprintf(buff + n, sizeof(buff) - n. : cant open, *s\n .

15 strerror(errno)):

16 n - strlen(buff):

17 WriteCwritefd. buff, n):

18 } else {

19 /* файл успешно открыт и копируется в канал */

20 while ( (п = ReadCfd, buff. MAXLINE)) > 0)

21 WriteCwritefd, buff, n):

22 Close(fd):

23 }

24 }

Считывание полного имени файла из канала

8-11 Записанное в канал клиентом имя файла считывается сервером и дополняется завершающим символом с кодом О (null-terminated). Обратите внимание, что



write

mi] П<ойносторонний канал х 1 fd[0]

Рис. 4.8. Односторонний канал

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

write

read

двусторонний канал

read

write

Рис. 4.9. Одна из возможных реализаций двустороннего канала (неправильная)

функция read возвращает данные, как только они помещаются в поток, не ожидая накопления некоторого их количества (MAXLINE в данном примере).

Открытие файла, обработка возможной ошибки

12-17 Файл открывается для чтения и при возникновении ошибки сообщение о ней возвращается клиенту с помощью канала. Для получения строки с соответствующим значению переменной еггпо сообщением об ошибке вызывается функция strerror (в книге [24, с. 690-691] вы найдете более подробный рассказ об этой функции).

Копирование из файла в канал

18-23 При успешном завершении работы функции open содержимое файла копируется в канал.

Ниже приведен результат работы программы в случае наличия файла с указанным полным именем и в случае возникновения ошибок: Solaris % mainpipe

/etc/inet/ntp.conf файл, состоящий из двух строк

multicastclient 224.0.1.1 driftfile /etc/inet/ntp.drift Solaris % mainpipe

/etc/shadow файл, на чтение которого нет разрешения

/etc/shadow; cant open. Permission denied Solaris % mainpipe

/no/such/file несуществующий файл

/по/such/file: cant open. No such file or directory

4.4. Двусторонние каналы

в предыдущем разделе мы отметили, что во многих системах реализованы двусторонние каналы. В Unix SVR4 это обеспечивается самой функцией pipe, а во многих других ядрах - функцией socketpair. Но что в действительности представляет собой двусторонний канал? Представим себе сначала однонаправленный канал, изображенный на рис. 4.8.



Такая реализация вызовет проблемы, например, в программе листинга А.14. Здесь требуется двусторонняя передача информации, причем потоки данных должны быть независимы, В противном случае некоторый процесс, записав данные в канал и перейдя затем в режим чтения из этого же канала, рискует считать обратно те же данные, которые были им только что туда записаны.

На рис. 4.10 изображена правильная реализация двустороннего канала.


X односторонний канал х

>fd[1]

X односторонний канал X -jjg

fd[0]

Рис. 4.10. Правильная реализация двустороннего канала

Здесь двусторонний канал получается из объединения двух односторонних. Все данные, записываемые в fd[l], будут доступны для чтения из fd[0], а данные, записываемые в fd[0], будут доступны для чтения из fd[l].

Программа в листинге 4.4 иллюстрирует использование одного двустороннего канала для двусторонней передачи информации.

Листинг 4.4. Двусторонняя связь через двусторонний канал

pipe/fduplex.c

1 #include unpipc.h

2 int

3 mainCint argc. char **argv)

5 int fd[2], n;

6 char c;

7 pid t childpid;

8 PipeCfd); /* предполагается двусторонний канал Снапр.. SVR4) */

9 if С Cchildpid - ForkO) - 0) { /* child */

10 sleepC3);

11 if С Cn - ReadCfdCO]. Sc. D) J- 1)

12 err quitC child: read returned *d . n);

13 printfC child read %c\n . c);

14 WriteCfd[0], c , 1);

15 exitCO);

16 }

17 /* родитель */

18 WriteCfd[l], p . 1):

19 if С Cn - ReadCfd[l]. &c, D) !- 1)

20 err quitС parent: read returned *d , n);

21 printfС parent read *c\n , c):

22 exitCO):

23 }

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



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 [ 18 ] 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.