其他进程间通信https://www.cnblogs.com/xiaoxiaolinux/p/13714608.html

XSI中有三种通信机制:消息队列、信号量数组、共享内存。可以用于有血缘关系的进程间通信,也可以用于无血缘关系的进程间通信。通过命令“ipcs”可以查看当前系统中有无这三种机制。如图所示,键(key)是保证无血缘关系的进程间通信的关键,是为了通信双方都能拿到同一个通信机制。

 

 如何拿到key?

#include<sys/ipc.h>
key_t   ftok(const char*pathname,int id);//pathname是一个现有文件

1、message queue

  几个关键的函数

#include<sys/msg.h>
int msgget(ket_t key,int flag);//成功返回消息队列id,失败返回-1

//向消息队列发送数据
int msgsnd(int msgid,const void* ptr,size_t bytes,int flag);
//参数1,msgget的返回值,参数2,发送数据的结构体指针,参数3,数据的实际大小,
//参数4,可以指定非阻塞IPC_NOWAIT,如果消息队列已满,指定非阻塞可以使函数立即返回EAGAIN
//参数4,也可以指定MSG_NOERROR,如果消息过长可以截断为所指定的bytes
//接受消息 size_t msgrcv(int msgid,void *ptr,size_t bytes,long type,int flag);
//参数2指向事先定义好的结构体,总体分为两部分,一是long型的mtype,二是message data
//参数4可以指定接受哪一个数据包,由此可见,“消息队列”并非是“队列”,其余与上述类似 int msgctl(int msgid,int cmd,struct msqid_ds *buf); //cmd指定IPC_RMID表示删除消息队列

  消息队列的消息结构。

struct msg
{
    long mtype; //说明消息的类型
    char  text[521];//消息的数据部分         
}

  一个demo

  协议部分

  1 #ifndef _PROTO_H_
  2 #define _PROTO_H_
  3 
  4 #define PATHNAME  "/etc/services" 
  5 #define KEYPROJ     'a'       //产生key的材料
  6 struct msg_st
  7 {
  8     long mtype;
  9     char name[64];
 10     int chinese;
 11     int math;
 12 };
 13 #endif

  接受方

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include"proto.h"
  4 #include<sys/types.h>
  5 #include<sys/ipc.h>
  6 #include<sys/msg.h>
  7 #include<signal.h>
  8 int msgid;
  9 //当按下ctrl+c时销毁消息队列
 10 void func(int signum)
 11 {
 12 
 13     msgctl(msgid,IPC_RMID,NULL);
 14     puts("cath");
 15 }
 16 int main()
 17 {
 18     key_t key;
 19     struct msg_st sbuf;
 20     //注册一个信号捕捉函数
 21     struct sigaction act;
 22     act.sa_handler=func;
 23     sigemptyset(&(act.sa_mask));
 24     act.sa_flags=0;
 25     sigaction(SIGINT,&act,NULL);
 26     //产生双方约定的key
 27     key=ftok(PATHNAME,KEYPROJ);
 28     if(key<0)
 29     {
 30         perror("ftok()");
 31         exit(1);
 32     }
 33     //先运行的一方创建消息队列
 34     msgid=msgget(key,IPC_CREAT|0600);
 35     if(msgid<0)
 36     {
 37         perror("magget()");
 38         exit(1);
 39     }
 40     while(1)
 41     {
 42         //从消息队列中取数据
 43         if(msgrcv(msgid,&sbuf,sizeof(sbuf)-sizeof(long),0,0)<0)
 44         {
 45             perror("msgrcv()");
 46             exit(0);
 47         }
 48         printf("name=%s\n",sbuf.name);
 49         printf("chinese=%d\n",sbuf.chinese);
 50         printf("math=%d\n",sbuf.math);
 51 
 52     }
 53 
 54     exit(0);
 55 
 56 }     

  发送方

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<sys/types.h>
  4 #include"proto.h"
  5 #include<string.h>
  6 #include<sys/ipc.h>
  7 int main()
  8 {
  9     key_t key;
 10     struct msg_st buf;
 11     //产生消息
 12     buf.mtype=1;
 13     strcpy(buf.name,"liming");
 14     buf.chinese=90;
 15     buf.math=90;
 16 
 17     key=ftok(PATHNAME,KEYPROJ);
 18     if(key<0)
 19     {
 20         perror("ftok()");
 21         exit(1);
 22     }
 23     //接受方已经创建好了一个消息队列
 24     int msgid=msgget(key,0);
 25     if(msgid<0)
 26     {
 27         perror("magget()");
 28         exit(1);
 29     }
 30     if(msgsnd(msgid,&buf,sizeof(buf)-sizeof(long),0)<0)
 31     {
 32         perror("msgsnd()");
 33         exit(1);
 34     }
 35     puts("ok");
 36     exit(0);
 37 }

 

 2、semaphore arrays

  信号量是一个计数器,用于为多个进程提供对共享数据的访问。常用的信号量是二元信号量,控制单个资源,初始值为1。XSI的信号量要指定信号量的数量和初始值。

  几个重要的函数

#include<sys/sem.h>
int semget(key_t key,int sems,int flag); //参数1,如果是血缘进程可以不用约定key,使用宏IPC_PRIVATE;参数2,信号量个数;

//对信号量设初始值或者删除信号量
int semctl(int semid,int semnum,int cmd,....);//参数2 指定SETVAL/IPC_RMID

//P、V操作由此函数完成
int semop(int semid,struct sembuf semoparray[] ,size_t nops);//c参数3,数组中操作的数量

struct sembuf
{
   unsigned short  sem_num; //信号量数组下标
   short  sem_op; //如果是正值,表示释放资源,如果是负值,表示想要获取资源
    short  sem_flg;         //IPC_NOWAIT,SEM_UNDO
   
}

  一个demo

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<fcntl.h>
  5 #include<sys/wait.h>
  6 #include<sys/ipc.h>
  7 #include<sys/types.h>
  8 #include<sys/sem.h>
  9 #include<errno.h>
 10 static int semid;
 11 static void P()
 12 {
 13     struct sembuf op;
 14     op.sem_num=0;
 15     op.sem_op=-1;
 16     op.sem_flg=0;
 17     while(semop(semid,&op,1)<0)
 18     {
 19         if(errno!=EINTR|| errno!=EAGAIN)
 20         {
 21             perror("semop error");
 22             exit(1);
 23         }
 24     }
 25 }
 26 static void V()
 27 {
 28     struct sembuf op;
 29     op.sem_num=0;
 30     op.sem_op=1;
 31     op.sem_flg=0;
 32     if(semop(semid,&op,1)<0)
 33     {
 34         perror("semop");
 35         exit(1);
 36     }
 37 }
 38 static void func_add()
 39 {
 40     FILE *fp;
 41     int fd;
 42     char buf[BUFSIZ];
 43     fp=fopen("/tmp/out","r+");
 44     if(NULL==fp)
 45     {
 46         perror("fopen()");
 47         exit(1);
 48     }
 49     P();
 50     fgets(buf,BUFSIZ,fp);
 51     fseek(fp,0,SEEK_SET);
 52     fprintf(fp,"%d\n",atoi(buf)+1);
 53     V();
 54     fclose(fp);
 55     return ;
 56 }
 57 int main()
 58 {
 59     int i;
 60     pid_t pid;
 61     semid= semget(IPC_PRIVATE,1,0600);//有一个资源
 62     if(semid<0)
 63     {
 64         perror("semget()");
 65         exit(1);
 66     }
 67     if(semctl(semid,0,SETVAL,1)<0)
 68     {
 69         perror("semctl()");
 70         exit(1);
 71     }//初始化
 72     //产生20个子进程对用一文件执行读写操作
 73     for(i=0;i<20;i++)
 74     {
 75         pid=fork();
 76         if(pid==0)
 77         {
 78             func_add();
 79             exit(0);
 80         }
 81         if(pid<0)
 82         {
 83             perror("fork()");
 84             exit(1);
 85         }
 86 
 87     }
 88     for(i=0;i<20;i++)
 89     {
 90         wait(NULL);
 91     }
 92     //删除信号量
 93     semctl(semid,0,IPC_RMID);
 94     exit(0);
 95 }

3、共享内存

  使用函数mmap创建的共享映射区是在多进程将一个文件映射到他们的地址空间。XSI共享内存不需要相关文件,XSI共享存储段是内存的匿名段。

  几个重要的函数

#include<sys/shm.h>
//获取共享存储标识符
int shmget(key_t key,size_t size,int flag);

//进程调用此函数将共享存储段映射到他的地址空间中
void *shmat(int shmid,const void *addr,int flag);
//参数2默认填0,参数3如果指定SHM_RDONLY,以只读方式连接共享存储段 //与共享存储段分离 int shmdt(const void *addr); //对共享存储段操作,一般是删除该共享存储 int shmctl(int shmid,int cmd,struct shmid_ds* buf);
  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #include<sys/wait.h>
  5 #include<sys/ipc.h>
  6 #include<sys/shm.h>
  7 #include<unistd.h>
  8 int main()
  9 {
 10     pid_t pid;
 11     int shmid;
 12     void* ptr;
 13     shmid=shmget(IPC_PRIVATE,BUFSIZ,0600);
 14     if(shmid<0)
 15     {
 16         perror("shmget()");
 17         exit(1);
 18     }
 19     pid=fork();
 20     if(pid<0)
 21     {
 22         perror("fork()");
 23         exit(1);
 24     }
 25     else if(pid==0)
 26     {
 27         ptr=shmat(shmid,NULL,0);
 28         if(ptr==(void *)-1)
 29         {
 30             perror("shmat()");
 31             exit(1);
 32         }
 33         strcpy(ptr,"liming");
 34         shmdt(ptr);
 35         exit(0);
 36     }else
 37     {
 38         wait(NULL);
 39         ptr=shmat(shmid,NULL,0);
 40         if(ptr==(void*)-1)
 41         {
 42             perror("shmat");
 43             exit(1);
 44         }
 45         puts(ptr);
 46         shmdt(ptr);
 47         shmctl(shmid,IPC_RMID,NULL); //父进程负责销毁
 48         exit(0);
 49 
 50     }
 51 }

   在这个例子中,并没有调用ftok()来产生一个key,而指定一个匿名IPC,因为在具有血缘关系的两个进程通信并不关心key是多少,只要给我一个key能产生同一个id就行。