Рейтинговые книги
Читем онлайн Linux: Полное руководство - Денис Колисниченко

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 135 136 137 138 139 140 141 142 143 ... 158

#include <stdio.h>

#include <stdlib.h>

#include <sys/stat.h>

#include <unistd.h>

#include <linux/stat.h>

/* Наш канал называется FIFO, он будет создан в текущем

 каталоге */

#define FIFO "FIFO"

void main(void) {

 FILE * fp;

 /* Буфер для чтения */

 char buf[126];

/* Создаем канал, если он еще не создан,

 права доступа 0666 */

 umask(0);

 mknod(FIFO, S_IFIFO|0666, 0);

 /* Ожидаем данные */

 while(1) {

  fp = fopen(FIFO, "r");

  fgets(buf, 128, fp);

  printf("Получена строка: %sn", buf);

  fclose(fp);

 }

}

Теперь рассмотрим процесс-писатель, который будет записывать данные в FIFO-канал. Этот процесс не завершится до тех пор, пока процесс-читатель не прочитает их:

Листинг 26.4. Процесс-писатель writefifo.c

#include <stdio.h>

#include <stdlib.h>

#define FIFO "FIFO"

void main(int argc, char *argv[]) {

 FILE *fp;

 if (argc != 2) {

  printf("USAGE: writefifo <string>n");

  exit(1);

 }

 fp = fopen(FIFO, "w");

 fputs(argv[1], fp);

 fclose(fp);

}

Запустите процесс-читатель, затем перейдите на другую консоль и запустите «писателя» с аргументом — строкой «info». На первой консоли вы увидите сообщение:

Получена строка: info

При использовании каналов FIFO нужно учитывать механизм их блокирования. Если процесс открыл канал для записи, то он блокируется до тех пор, пока другой процесс не откроет его для чтения. Аналогично, если какой-то процесс откроет FIFO-канал для чтения, он будет блокирован, пока другой процесс не запишет в канал данные. Если блокировка процесса нежелательна, можно использовать опцию O_NONBLOCK.

open(fd, O_NONBLOCK);

Ясное дело, что тогда нужно немного модифицировать исходный код: вызовы fclose(), fputs(), fgets() использовать уже нельзя, вместо них нужно использовать соответствующие вызовы close(), write(), read().

И последнее, что нужно помнить при программировании FIFO-каналов: идеология FIFO-каналов предполагает наличие «читателей» и «писателей». Если «писатель» пишет в канал, у которого нет «читателя», из ядра будет послан сигнал SIGPIPE.

26.4. Основные принципы System V IPC

Каждый объект IPC, то есть семафор, очередь сообщений или разделяемый сегмент памяти, имеет свой идентификатор, позволяющий ядру однозначно идентифицировать объект. Идентификатор уникален только для объектов данного типа, а не для всей системы. Например, в системе может быть очередь сообщений с идентификатором «111» и семафор с ID «111», но никогда не будет двух разных очередей с идентификатором «111».

Для получения уникального идентификатора системе нужен ключ (IPC Key), который согласовывается с процессом-сервером и процессом-клиентом. Ключ осуществляет связь между процессом-сервером и процессом- клиентом подобно тому, как маршрутизатор осуществляет связь между двумя компьютерами в разных подсетях.

Ключ генерируется приложением самостоятельно. Для этого используется функция ftok():

key_t ftok( char *pathname, char proj);

В случае успеха возвращается ключ, а в случае ошибки -1.

При создании ключа нужно учитывать, что сгенерированные ключи могут повторяться, поэтому после получения нового ключа нужно проверить, не используется ли он уже.

Ключ генерируется на основе номера inode первого аргумента и символов второго. Это не гарантия уникальности, поэтому и получается, что функция может возвращать уже используемый ключ.

key_t key1;

key_t key2;

key1 = ftok("/tmp/app", 'a');

key2 = ftok(".", 'd');

Просмотреть статус всех объектов IPC можно с помощью команды ipcs, выводящей состояние всех разделяемых сегментов памяти, семафоров и очередей сообщений.

Для удаления объекта IPC используется команда

ipcrm <msg | sem | shm> IPC_ID

Так как идентификатор IPC уникален только для объектов IPC определенного типа, вы должны указать тип объекта (msg — очередь сообщений, sem — семафор, shm — сегмент памяти) и его идентификатор.

Для работы с объектами IPC не забудьте подключить следующие заголовочные файлы:

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h> /* для очередей */

#include <sys/sem.h> /* для семафоров */

#include <sys/shm.h> /* для разделяемых сегментов памяти */

26.5. Очереди сообщений

26.5.1. Основные структуры ядра для работы с очередями

Очередь сообщений — это связный список, находящийся в адресном пространстве ядра. Каждая очередь имеет свой уникальный идентификатор IPC.

Структура ядра msgbuf (описана в файле /usr/src/linux/include/linux/msg.h) является буфером сообщений:

struct msgbuf {

 long mtype; /* тип сообщения */

 char mtext[1]; /* текст сообщения */

};

Тут все ясно: тип сообщения и само сообщение. Используя тип сообщения, вы можете помещать в одну очередь разные сообщения, а не создавать еще одну очередь. Например, у нас есть два приложения — клиент и сервер. Вы можете использовать для них одну и ту же очередь: сообщения клиента будут с номером 1 (mtype = 1), а сообщения сервера — с номером 0 (mtype = 0).

Ясное дело, что сообщения из одного символа нас не устраивают, поэтому вы можете переопределить структуру msgbuf в своей программе:

struct my_buf {

 long mtype;

 char mtext[128];

}

Вы также можете добавлять новые поля в эту структуру (но только в своей программе! Код ядра модифицировать не нужно):

struct my_buf {

 long mtype;

 char mtext[128];

 char info[50];

 int status;

}

He бойтесь создавать свои структуры: ядру все равно, с какими данными работать, вам нужно учитывать только максимальный размер сообщения, который определен в файле /usr/src/linux/include/linux/msg.h:

#define MSGMAX 4056

4056 байтов — это максимальный размер не ваших данных, а всей структуры. включая тип сообщения. Размер типа long равен 4 байтам.

Сами сообщения хранятся ядром в структуре msg, которая также определена в файле msg.h:

struct msg {

 struct msg *msg_next; /* указатель на след. сообщение

                          в очереди */

 long msg_type;  /* тип сообщения */

 char *msg_spot; /* адрес самого сообщения (текста) */

 short msg_ts;   /* размер сообщения (текста) */

};

Сообщения хранятся в виде односвязного списка. Первый член структуры msg_next — это указатель на следующее сообщение в очереди. Второй член msg_type — это тип сообщения, такой же, как в структуре msg_buf.

Следующий член структуры — это указатель на начало текста сообщения, а последний член msg_ts — размер текста сообщения.

Каждый тип объекта IPC представляется в ядре определенной структурой. Для очередей сообщений это структура msqid_ds (описана в файле /usr/src/linux/include/linux/msg.h).

struct msqid_ds {

 struct ipc_perm msg_perm; /* информация о правах

                              доступа */

 struct msg *msg_first; /* указатель на первое сообщение

                           в очереди */

 struct msg *msg_last; /* указатель на последнее сообщение

                          в очереди*/

 time_t msg_stime; /* время последнего вызова msgsnd */

 time_t msg_rtime; /* время последнего вызова msgrcv */

 time_t msg_ctime; /* время последнего изменения */

 struct wait_queue *wwait;

 struct wait_queue *rwait;

 ushort msg_cbytes;

 ushort msg_qnum;

 ushort msg_qbytes; /* максимальное число байтов на очередь */

 ushort msg_lspid;  /* pid последнего испустившего msgsnd */

 ushort msg_lrpid;  /* последний полученный pid */

};

♦ msg_perm

Это структура типа ipc_perm (ipc_perm определена в файле linux/ipc.h). Данная структура содержит информацию о владельце и правах доступа:

struct ipc_perm {

 key_t key;

 ushort uid;  /* uid и gid владельца */

 ushort gid;

 ushort cuid; /* uid и gid создателя */

 ushort cgid;

 ushort mode; /* режим доступа */

 ushort seq;  /* системное поле. Вас оно не касается. */

};

♦ msg_ftrst

Указатель на первое сообщение в очереди.

♦ msg_last

Указатель на последнее сообщение в очереди.

♦ msg_stime

Время отправки последнего сообщения из очереди,

♦ msg_rtime

Время последнего изъятия сообщения из очереди.

1 ... 135 136 137 138 139 140 141 142 143 ... 158
На этой странице вы можете бесплатно читать книгу Linux: Полное руководство - Денис Колисниченко бесплатно.
Похожие на Linux: Полное руководство - Денис Колисниченко книги

Оставить комментарий