logo
Операционные системы

0666 Определяет права доступа */

msgid = msgget(key, 0666 | IPC_CREAT | IPC_EXCL);

/* запускаем вечный цикл */

for(;;)

{

gets(str); /* читаем из стандартного ввода строку */

/* и копируем ее в буфер сообщения */

strcpy(Message.Data, str);

/* анализируем первый символ прочитанной строки */

switch(str[0])

{

case 'a':

case 'A':

/* устанавливаем тип 1 для ПРОЦЕССА A*/

Message.mtype = 1;

/* посылаем сообщение в очередь */

msgsnd(msgid, (struct msgbuf*) (&Message),

strlen(str)+1, 0);

break;

case 'b':

case 'B':

/* устанавливаем тип 2 для ПРОЦЕССА A*/

Message.mtype = 2;

msgsnd(msgid, (struct msgbuf*) (&Message),

strlen(str)+1, 0);

break;

case 'q':

case 'Q':

Message.mtype = 1;

msgsnd(msgid, (struct msgbuf*) (&Message),

strlen(str)+1, 0);

Message.mtype = 2;

msgsnd(msgid, (struct msgbuf*) (&Message),

strlen(str)+1, 0);

/* ждем получения сообщений

процессами А и В */

sleep(10);2

/* уничтожаем очередь */

msgctl(msgid, IPC_RMID, NULL);

exit(0);

default:

/* игнорируем остальные случаи */

break;

}

}

}

/* ПРИНИМАЮЩИЙ ПРОЦЕСС A (процесс B будет аналогичным) */

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/message.h>

#include <stdio.h>

struct

{

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

char Data[256]; /* сообщение */

} Message;

int main(int argc, char **argv)

{

key_t key;

int msgid;

/* получаем ключ по тем же параметрам */

key = ftok("/usr/mash",'s');

/*подключаемся к очереди сообщений */

msgid = msgget(key, 0666);

/* запускаем вечный цикл */

for(;;)

{

/* читаем сообщение с типом 1 для ПРОЦЕССА A */

msgrcv(msgid, (struct msgbuf*) (&Message), 256, 1, 0);3

printf("%s", Message.Data);

if(Message.Data[0] == 'q' || Message.Data[0] == 'Q')

break;

}

return 0;

}

Пример. Очередь сообщений. Модель «клиент-сервер». В приведенном ниже примере имеется совокупность взаимодействующих процессов. Эта модель несимметричная: один из процессов назначается сервером, и его задачей становится обслуживание запросов остальных процессов-клиентов. В данном примере сервер принимает запросы от клиентов в виде сообщений (из очереди сообщений) с типом 1. Тело сообщения-запроса содержит идентификатор клиентского процесса, который выслал данный запрос. Для каждого запроса сервер генерирует ответ, которое также посылает через очередь сообщений, но посылаемое сообщение будет иметь тип, равный идентификатору процесса-адресата. В свою очередь, клиентский процесс будет брать из очереди сообщений сообщения с типом, равным его идентификатору.

/* СЕРВЕР */

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

#include <stdlib.h>

#include <string.h>

int main(int argc, char **argv)

{

struct

{

long mestype;

char mes[100];

} messageto;

struct

{

long mestype;

long mes;

} messagefrom;

key_t key;

int mesid;

key = ftok("example", 'r');

mesid = msgget (key, 0666 | IPC_CREAT | IPC_EXCL );

while(1)

{

msgrcv(mesid, &messagefrom, sizeof(messagefrom) –

sizeof(long), 1, 0);

messageto.mestype = messagefrom.mes;

strcpy(messageto.mes, "Message for client");

msgsnd (mesid, &messageto, sizeof(messageto) –

sizeof(long),0);

}

}

/* КЛИЕНТ */

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int main(int argc, char **argv)

{

struct

{

long mestype;

long mes;

} messageto;

struct

{

long mestype;

char mes[100];

} messagefrom;

key_t key;

int mesid;

long pid = getpid();

key = ftok("example", 'r');

mesid = msgget (key, 0666);

messageto.mestype = 1;

messageto.mes = pid;

msgsnd(mesid, &messageto, sizeof(messageto) –

sizeof(long),0);

msgrcv(mesid,&messagefrom, sizeof(messagefrom) –

sizeof(long),pid,0);

printf("%s", messagefrom.mes);

return 0;

}

В серверном процессе декларируются две структуры для принимаемого (meassagefrom) и посылаемого (messageto) сообщений, а также ключ key и дескриптор очереди сообщений mesid. Затем сервер предпринимает традиционные действия: получает ключ, а по нему — дескриптор очереди сообщений. Затем он входит в бесконечный цикл, в котором и обрабатывает клиентские запросы. Каждая итерация цикла выглядит следующим образом. Из очереди выбирается сообщение с типом 1 (это сообщения с запросами от клиентов). Из тела этого сообщения считывается информация об идентификаторе клиента, и этот идентификатор сразу заносится в поле типа посылаемого сообщения. Затем сервер генерирует тело посылаемого сообщения, после чего отправляет созданное сообщение в очередь. На этом итерация цикла завершается.

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