IPC Linux без проблем, межпроцессное взаимодействие,описание IPC, очереди сообщений, исходный код, OC Fedora, KDeveloper

1.Краткая описание механизмов (IPC)

Для общения между процессами, группами процессов (передача данных, команд), спецификация System V (SysV) UNIX определяет три механизма для IPC, которые обычно называют SysV IPC:

- очереди сообщений
- семафоры
- совместно используемая память

Далее, слово ресурс означает сущность, созданную в результате работы одного из этих механизмов.

1.1 Права доступа к ресурсу
Для каждого ресурса система использует обобщенную структуру типа struct ipc_perm для хранения информации, которая необходима для определения прав на выполнение какой-либо операции ipc. Структура ipc_perm определяется в заголовочном файле <sys/ipc.h> и содержит следующие поля:

ushort cuid; /* идентификатор пользователя, создавшего ресурс*/
ushort cgid; /* идентификатор группы, создавшей ресурс */
ushort uid; /* идентификатор владельца */
ushort gid; /* идентификатор группы */
ushort mode; /* права на чтение/запись */

В поле mode структуры ipc_perm рабочими являются младшие 9 битов и представляют собой права доступа к ресурсу для процесса, сделавшего ipc вызов. Права интерпретируются так:

0400 Чтение для пользователя
0200 Запись для пользователя
0040 Чтение для группы
0020 Запись для группы
0004 Чтение для других
0002 Запись для других


IPC_CREAT 
Создать запись, если ключ не существует.
IPC_EXCL
Ошибка, если ключ существует.
IPC_NOWAIT
Ошибка, если запрос должен ждать.
IPC_PRIVATE
Личный ключ.
IPC_RMID
Удалить ресурс.
IPC_SET
Установить опции ресурса.
IPC_STAT
Получить опции ресурса.


Заметим, что IPC_PRIVATE имеет тип key_t, в то время как все остальные символьные константы являются полями-флагами, для которых может выполняться операция логического сложения в переменную типа int.

1.2 Очереди Сообщений
Очередь сообщений идентифицируется уникальным положительным целым числом (msqid), связанным со структурой данных типа struct msqid_ds, которая определяется в заголовочном файле <sys/msg.h>, и которая содержит следующие поля:


struct ipc_perm msg_perm;
ushort msg_qnum; /* количество сообщений в очереди */ 
ushort msg_qbytes; /* максимальное количество байт в очереди */ 
ushort msg_lspid; /* pid, идентификатор процесса, выполнившего последний вызов msgsnd */ 
ushort msg_lrpid; /* pid, идентификатор процесса, выполнившего последний вызов msgrcv */ 
time_t msg_stime; /* время последнего вызова msgsnd */ 
time_t msg_rtime; /* время последнего вызова msgrcv */ 
time_t msg_ctime; /* время последнего изменения */ 
msg_perm
Структура ipc_perm задает права доступа к очереди сообщения.
msg_qnum
Количество сообщений, которые в данный момент находятся в очереди.
msg_qbytes
Максимальное количество байтов текста сообщения, которое допускается в очереди.
msg_lspid
Идентификатор процесса, который выполнил последний системный вызов msgsnd.
msg_lrpid
Идентификатор процесса, который выполнил последний системный вызов msgrcv.
msg_stime
Время, когда был выполнен последний системный вызов msgsnd.
msg_rtime
Время, когда был выполнен последний системный вызов msgcv.
msg_ctime
Время, когда был выполнен последний системный вызов, который изменил в структуре поле msqid_ds.

1.3 Списки семафоров
Список семафоров идентифицируется уникальным положительным целым числом (semid), связанным со структурой данных типа struct semid_ds, которая определяется в заголовочном файле <sys/sem.h> и которая содержит следующие поля:


struct ipc_perm sem_perm;
time_t sem_otime; /* время последней операции */ 
time_t sem_ctime; /* время последнего изменения */ 
ushort sem_nsems; /* количество семафоров в списке */ 
sem_perm
Структура ipc_perm, которая задает права доступа к списку семафоров.
sem_otime
Время последнего системного вызова semop.
sem_ctime
Время последнего системного вызова semctl, который изменяет значение какого-либо из полей структуры или один из семафоров в списке.
sem_nsems
Количество семафоров в списке. Семафоры в списке нумеруются положительными целыми числами от нуля до sem_nsems-1.

Семафор -- это структура данных типа struct sem, которая содержит следующие поля:


ushort semval; /* значение семафора */
short sempid; /* pid последней операции */ 
ushort semncnt; /* Количество ожидающих увеличения semval */ 
ushort semzcnt; /* Количество ожидающих установки semval в нуль */ 
semval
Значение семафора: неотрицательное целое число.
sempid
Идентификатор последнего процесса, который работал с данным семафором.
semncnt
Количество процессов, приостановленных в ожидании увеличения semval.
semznt
Количество процессов, приостановленных в ожидании установки значения semval в нуль.

1.4 Сегменты Разделяемой Памяти
Сегмент разделяемой памяти идентифицируется уникальным положительным целым числом (shmid), которое связано со структурой данных типа struct shmid_ds, которая определяется в заголовочном файле <sys/shm.h> и которая содержит следующие поля:

struct ipc_perm shm_perm; 
int shm_segsz; /* размер сегмента */ 
ushort shm_cpid; /* pid создателя */ 
ushort shm_lpid; /* pid последней операции */ 
short shm_nattch; /* Количество подключенных в данный момент */ 
time_t shm_atime; /* время последнего подключения */ 
time_t shm_dtime; /* время последнего отключения */ 
time_t shm_ctime; /* время последнего изменения */ 
shm_perm
Структура ipc_perm, которая задает права доступа к разделяемому сегменту памяти.
shm_segsz
Размер разделяемого сегмента памяти в байтах.
shm_cpid
Идентификатор процесса, который создал разделяемый сегмент памяти.
shm_lpid
Идентификатор последнего процесса, который делал системные вызовы shmat или shmdt.
shm_nattch
Количество процессов, которые в данный момент подключены к данному разделяемому сегменту памяти.
shm_atime
Время последнего системного вызова shmat.
shm_dtime
Время последнего системного вызова shmdt.
shm_ctime
Время последнего системного вызова shmctl, который изменил shmid_ds.


2.Передача сообщений через очереди

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

Структура cообщений:
Сообщения должны состоять из длинного целого, за которыми следует содержимое сообщения:
/*
//структура очереди
#define MSGCMD 200
typedef struct my_msgbufer
{
long mtype;
struct{
char mcom[MSGCMD];
char mzn1[MSGCMD];
char mzn2[MSGCMD];
} info;
} message_buf;

// создаем новую структуру
message_buf cmyb;
*/


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

/*
smyb.mtype = 1;
*/


Для работы необходимо создать очередь (пример void serv_crmes(key_t key)), c ключом key_t,
флаг для создания очереди int smsgflg = IPC_CREAT | 0666;

*/
// создание очереди сообщений для сервера
void serv_crmes(key_t key)
{
smsqid = msgget(key,smsgflg);
if (smsqid < 0 )
{ perror("ошибка очереди сервера");
exit(1);
}
}
*/


Вносим значения в нашу структуру:

/*
sprintf(smyb.info.mcom,"%s"," ");
sprintf(smyb.info.mzn1,"%s"," ");
sprintf(smyb.info.mzn2,"%s"," ");
*/


Выполняем отправку сообщения (void sl_send_mes(key_t key)), c ключом key_t.

// передача сообщений
void sl_send_mes(key_t key)
{
printf("Клиент послал :\r\n");
printf("команда %s \r\n",smyb.info.mcom);
printf("значение1 %s \r\n",smyb.info.mzn1);
printf("значение2 %s \r\n",smyb.info.mzn2);

sbuf_length = sizeof(smyb.info);
if (msgsnd(smsqid,&smyb,sbuf_length, IPC_NOWAIT) < 0)
{
perror("smsgsnd");
}
}


Сообщение отправлено!

Последовательность выполнения команд изложена на примере работы клиент - сервера (client.cpp, server.cpp), исходный код находится в форуме..

 

client.cpp

//============================================================================
// Name        : client.cpp
// Author      : Ardatov V.I.
// Version     :
// Copyright   : www.avicorp.ru
// Description : Client in C++, Fedora ,Ansi-style
//============================================================================

#include <boost/thread/mutex.hpp>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>

//структура очереди
#define MSGCMD 200
// индекс очереди клиента
key_t ckey = 200;
// индекс очереди сервера
key_t skey = 100;

typedef struct my_msgbufer
{
 long mtype;

 struct{
     char mcom[MSGCMD];
     char mzn1 [MSGCMD];
     char mzn2 [MSGCMD];    
 } info;
 } message_buf;
 
 
 message_buf cmyb;
 message_buf smyb;

 size_t cbuf_length;
 size_t sbuf_length;

 
 int cmsqid;
 int smsqid;

// флаги создания
 int cmsgflg = 0666;
 int smsgflg = IPC_CREAT | 0666;



// создание очереди сообщений для программы
void client_crmes(key_t key)
{
cmsqid = msgget(key,cmsgflg);
if (cmsqid < 0 )
{  perror(\"очереди нет , не запущен сервер\");
}
}

// создание очереди сообщений для сервера
void serv_crmes(key_t key)
{
smsqid = msgget(key,smsgflg);
if (smsqid < 0 )
{  perror(\"ошибка очереди сервера\");
exit(1);
}
}

// передача сообщений
void sl_send_mes(key_t key)
{
         printf(\"Клиент послал :\\r\\n\");
         printf(\"команда   %s \\r\\n\",smyb.info.mcom);
         printf(\"значение1 %s \\r\\n\",smyb.info.mzn1);
         printf(\"значение2 %s \\r\\n\",smyb.info.mzn2);
         
         
    sbuf_length = sizeof(smyb.info);
    if (msgsnd(smsqid,&smyb,sbuf_length, IPC_NOWAIT) < 0)
    {
     perror(\"smsgsnd\");
    }

}


int main(int argc, char** argv)
{

// ждем аргументы запуска
if (argc <= 1)
{
printf(\"пример запуска ./client STATUS \\r\\n\");
printf(\"пример запуска ./client TERMINATE \\r\\n\");
exit (1);
 
}

// принимаем аргументы в temp
char temp[200];
sprintf(temp,\"%s\",argv[1]);

// счетчик
int counter = 0;

// создаем свою очередь сообщений
serv_crmes(skey);
smyb.mtype = 1;
sprintf(smyb.info.mcom,\"%s\",\" \");  
sprintf(smyb.info.mzn1,\"%s\",\" \");
sprintf(smyb.info.mzn2,\"%s\",\" \");


// какую команду получил
if (strcmp(temp,\"STATUS\") == 0)  sprintf(smyb.info.mcom,\"%s\",\"STATUS\");  
if (strcmp(temp,\"TERMINATE\") == 0)  sprintf(smyb.info.mcom,\"%s\",\"TERMINATE\");

// посылка сообщения
sl_send_mes(skey);

sleep(1);
       
return 0;
}

server.cpp

//============================================================================
// Name        : server.cpp
// Author      : Ardatov V.I.
// Version     :
// Copyright   : http://www.avicorp.ru
// Description : Sever IPC in C++, Fedora, Ansi-style
//============================================================================



#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <stdlib.h>
#include <stdio.h>

//структура очереди
#define MSGCMD 200
typedef struct my_msgbufer
{
 long mtype;
 struct{
     char mcom[MSGCMD];
     char mzn1[MSGCMD];
     char mzn2[MSGCMD];
 } info;

 } message_buf;


message_buf cmyb;
message_buf smyb;

size_t cbuf_length;
size_t sbuf_length;

 int cmsqid;
 int smsqid;

// индекс очереди клиента
key_t ckey = 100;
 // индекс очереди сервера
key_t skey = 200;


 int cmsgflg = 0666;
 int smsgflg = IPC_CREAT | 0666;




  struct param
{int idd;
 char *wn;
};

// создание очереди сообщений
void serv_crmes(key_t key)
{
smsqid = msgget(key,smsgflg);
if (smsqid < 0 )
{  perror(\"smsqid filed\");
exit(1);
}
}

// создание очереди для клиента
void cl_crmes(key_t key)
{
smsqid = msgget(key,cmsgflg);
if (smsqid < 0 )
{  perror(\"gsmsqid filed\");
exit(1);
}
}

// передача сообщений клиенту
void cl_send_mes(key_t key)
{

    cbuf_length = sizeof(cmyb.info);

    if (msgsnd(cmsqid,&cmyb,cbuf_length, IPC_NOWAIT) < 0)
    {
     perror(\"ctmsgsnd\");
    }

}


void *sread(void *arg)
{
  int ready = 0; int counter = 0;
serv_crmes(skey);
printf(\"сервер в ожидании !!! \\r\\n\");
  while (ready == 0)
{
  // пауза
 sleep(1);
  cl_crmes(ckey);
  counter++;
  if (counter == 100)  {printf(\" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! даже уснул барсук !!!!!!!!!!!!!!!!!!!!!! \\r\\n\");counter =0;}
 // если есть сообщения от клиента
    if (msgrcv(smsqid,&smyb,MSGCMD+MSGCMD+MSGCMD,1,IPC_NOWAIT) > 0)
        {
        printf(\"сервер получил:команда                  %s\\n\", smyb.info.mcom);
        printf(\"сервер получил:значение                 %s\\n\", smyb.info.mzn1);
                printf(\"сервер получил:значение                 %s\\n\", smyb.info.mzn2);

    // отрабатываем комманду STATUS
        if (strcmp(smyb.info.mcom,\"STATUS\") == 0)
            {  
    // пример статуса
            }                
    // отрабатываем комманду STATUS
         
    // отрабатываем команду TERMINATE
         if (strcmp(smyb.info.mcom,\"TERMINATE\") == 0)
            {  
                        // !!!!!!!!!!!! Выход из программы !!!!!!!!!!!!!!!!!!!!!!          
            exit(1);        
            }                
    // отрабатываем комманду TERMINATE        
         
}
else   {   printf(\"%d - (сервер) :   все спят в лесу ...\\r\\n\",counter);}
}
}


int main(int argc, char** argv)
{

int  result,result2;
pthread_t thread1, thread2;

struct param *p1 = new param;
p1->idd = 0;
p1->wn = (char*)\"0\";

// поток сервера
result  = pthread_create(&thread1, NULL ,sread , p1);

   for(;;)
        {
// бесконечный цикл
       sleep(0.1);  
    }
    return 0;
}

 

<На главную>

 

Расширения для Joomla