IPC通信-------初学者入门

一、共享内存

0、进程间的通讯方式

                管道、信号、共享内存、消息队列、信号量、套接字

管道和信号:只能用于两个进程间进行通讯

IPC:可以用于多个进程间进行通讯

1、IPC是用于多个进程间进行通讯的手段(Inter-Process Communication,进程间通信

        共享内存、消息队列、信号量

2、怎样去识别我的IPC

       比如有A B C三个进程,这三个进程要想通讯,可以使用共享内存、消息队列、信号量。三个进程访问同一块共享内存,要确定操作的是同一个共享内存,确定共享内存的唯一性   键值

3、键值的创建于意义

       唯一识别某个IPC

       保证我多个进程打开的是同一个IPC

4、查看指令

        ipcs -m 看Shared Memory 共享内存
        ipcs -s 看Semaphore Arrays 信号量
        ipcs -q 看Message Queues 消息队列
        删除指令ipcrm -q  id

1、获取一个键值 ftok        (file to key的缩写,即将文件转换成key)

        函数功能:获取一个键值

        函数头文件:#include <sys/types.h>
                             #include <sys/ipc.h>

        函数原型:key_t ftok(const char *pathname, int proj_id);

        函数的参数:const char *pathname:参考位置 (一般来说  写绝对路径)
                              int proj_id:参考的id  0-255

        函数的返回值:成功返回   键值                              失败返回  -1

       无论在任何位置 无论何时执行这个程序,只要你传入的参数是一致的   得到的键值就是唯一

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/ipc.h>
  4 #include<sys/shm.h>
  5 int main()
  6 {
  7         key_t keyid;
  8         int shmid;
  9         keyid=ftok("/home/ldw",5);
 10         if(keyid<0)
 11         {
 12                 perror("ftok");
 13                 return -1;
 14         }
 15         printf("keyid:%d\n",keyid);
 16         return 0;
 17 }
//keyid:83951618

共享内存

       他就是一个加强版的全局变量

       全局变量的特点

                1、作用域  是整个工程
                2、存放于全局区
                3、在作用域范围之内   不能重名

       共享内存:

                1:范围是整个计算机的进程
                2:整个计算里的进程都可以对她进行操作

                本质:本质就是内存里的一段空间

(1.作用域:系统下的所有的进程都可以访问到   2.一个进程对共享内存做修改   其他的进程都能看到)

2、创建一个共享内存 shmget

        函数功能:创建一块共享内存

        函数的头文件:#include <sys/ipc.h>
                                 #include <sys/shm.h>

        函数的原型:int shmget(key_t key, size_t size, int shmflg);

        函数的参数:key_t key:共享内存的键值
                             size_t size:要申请的共享内存的大小
                             int shmflg:标志                  IPC_CREAT | 0777
                        IPC_CREAT:没有则创建,有则打开

IPC(包括消息队列,共享内存,信号量)的xxxget()创建操作时,可以指定IPC_CREAT和IPC_EXCL选项。

以共享内存为例:①当只有IPC_CREAT选项打开时,不管是否已存在该块共享内存,则都返回该共享内存的ID,若不存在则创建共享内存;②当只有IPC_EXCL选项打开时,不管有没有该快共享内存,shmget()都返回-1;③所以当IPC_CREAT | IPC_EXCL时, 如果没有该块共享内存,则创建,并返回共享内存ID。若已有该块共享内存,则返回-1;

        函数的返回值:返回值为共享内存的id号,后续的操作要用到这个id号

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/ipc.h>
  4 #include<sys/shm.h>
  5 int main()
  6 {
  7         key_t keyid;
  8         int shmid;
  9         keyid=ftok("/home/ldw",5);
 10         if(keyid<0)
 11         {
 12                 perror("ftok");
 13                 return -1;
 14         }
 15         printf("keyid:%d\n",keyid);
 16         shmid=shmget(keyid,20,IPC_CREAT|0777);
 17         printf("shmid:%d\n",shmid);
 18         return 0;
 19 }
//keyid:83951618
//shmid:8683532

3、将共享内存映射到进程空间 shmat

        函数功能:将一段共享内存  映射到进程空间

        函数的头文件:#include <sys/types.h>
                                 #include <sys/shm.h>

        函数的原型:void *shmat(int shmid, const void *shmaddr, int shmflg);

        函数的参数:int shmid:共享内存的id
                             const void *shmaddr:你要映射到的进程空间的地址
                                一般来说   我们不清楚  进程的哪段内存空间是可用
                                一般这个位置  写0 表示由系统自动分配空间

                         int shmflg:一般来说  也是写0     表示共享内存可读写

        函数的返回值:返回的就是系统分配给你的空间的首地址

  1 #include<stdio.h>                                //写内容
  2 #include<sys/types.h>
  3 #include<sys/ipc.h>
  4 #include<sys/shm.h>
  5 #include<string.h>
  6 int main()
  7 {
  8         key_t keyid;
  9         int shmid;
 10         keyid=ftok("/home/ldw",5);
 11         if(keyid<0)
 12         {
 13                 perror("ftok");
 14                 return -1;
 15         }
 16         shmid=shmget(keyid,20,IPC_CREAT|0777);
 17         void *p=shmat(shmid,0,0);
 18         strcpy(p,"hello!");
 19         return 0;
 20 }
  1 #include<stdio.h>                          //读内容
  2 #include<sys/types.h>
  3 #include<sys/ipc.h>                        //读和写,在不同的终端中
  4 #include<sys/shm.h>
  5 #include<string.h>
  6 int main()
  7 {
  8         key_t keyid;
  9         int shmid;
 10         keyid=ftok("/home/ldw",5);
 11         if(keyid<0)
 12         {
 13                 perror("ftok");
 14                 return -1;
 15         }
 16         shmid=shmget(keyid,20,IPC_CREAT|0777);
 17         void *p=shmat(shmid,0,0);
 18         printf("said:%s\n",(char *)p);
 19         return 0;
 20 }
//said:hello!

4、解除映射 shmdt

        函数的功能:解除共享内存的映射

        函数的头文件:#include <sys/types.h>
                                 #include <sys/shm.h>

        函数的原型:int shmdt(const void *shmaddr);

        函数的参数:const void *shmaddr:系统分配给的内存空间的首地址

        函数的返回值:成功返回  0                         失败返回     -1

5、删除一个共享内存 shmctl

        函数功能:删除一个共享内存

        函数的头文件:#include <sys/ipc.h>
                                #include <sys/shm.h>

        函数原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);

        函数的参数:int shmid:共享内存的id
                             int cmd:IPC_RMID  删除共享内存
                             struct shmid_ds *buf:NULL

        函数的返回值:成功返回  0                                   失败返回  -1

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/ipc.h>
  4 #include<sys/shm.h>
  5 #include<string.h>
  6 int main()
  7 {
  8         key_t keyid;
  9         int shmid;
 10         keyid=ftok("/home/ldw",5);
 11         if(keyid<0)
 12         {
 13                 perror("ftok");
 14                 return -1;
 15         }
 16         shmid=shmget(keyid,20,IPC_CREAT|0777);
 17         void *p=shmat(shmid,0,0);
 18         strcpy(p,"hello!");
 19         shmdt(p);
 20         shmctl(shmid,IPC_RMID,NULL);
 21         return 0;
 22 }

二、信号量

       就是用来解决多个进程间资源的冲突的问题的,信号量就是用来解决进程间的同步与互斥问题的一种进程间通信机制。

信号量:本质就是一个普通的数值,你操作信号量其实就是在操作这个数值
              对这个数字可以进行加或者减的操作,对应的就是 P V操作

       当我的数字减到0的时候  表示无资源可以使用

              P操作

                     消耗一个信号量

                     如果信号量的值大于零,就给它减1;

                     如果的值为零,就挂起该进程的执行

              V操作:

                     释放一个信号量

1、创建或者打开一个信号量  semget

        函数功能:创建或者打开一个信号量

        函数的头文件:#include <sys/types.h>
                                #include <sys/ipc.h>
                                #include <sys/sem.h>

        函数的原型:int semget(key_t key, int nsems, int semflg);

        函数的参数:key_t key:键值
                             int nsems:你要创建的信号量的个数,这个位置一般填1
                             int semflg:IPC_CREAT | 0644     打开或创建信号量,并赋予权限

        函数的返回值:成功返回信号量的id        失败返回 -1           默认信号量的初值为0

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/ipc.h>
  4 #include<sys/sem.h>
  5 int main()
  6 {
  7         key_t keyid;
  8         int semid;
  9         keyid=ftok("/home/ldw",2);
 10         semid=semget(keyid,1,IPC_CREAT|0644);
 11         printf("semid:%d\n",semid);
 12         return 0;
 13 }   
//semid:32768

2、设置或者删除一个信号量  semctl

        函数功能:设置或者删除一个信号量

        函数头文件:#include <sys/types.h>
                             #include <sys/ipc.h>
                             #include <sys/sem.h>

        函数的原型:int semctl(int semid, int semnum, int cmd, ...);

         函数的参数:int semid:信号量的id
                              int semnum:要操作的信号量的数组的下标            一般写0
                              int cmd:① IPC_RMID:删除信号量、② SETVAL:设置信号量

①:如果此处为IPC_RMID:删除信号量,则后面第四个空没有参数
②:如果此处为SETVAL:设置信号量,则第四个参数需要传入一个共用体

     union semun {
               short val;                      /*SETVAL用的值*/(给信号量赋的初值)
               struct semid_ds* buf;   /*IPC_STAT、IPC_SET用的semid_ds结构(则是一个内核结构体)*/
               unsigned short* array;  /*SETALL、GETALL用的数组值*/
               struct seminfo *buf;      /*为控制IPC_INFO提供的缓存(表示信号量系统资源配置信息)*/
          } ;

        函数的返回值:成功返回  0                                 失败返回 -1

3、释放或者消耗一个信号量   semop

        函数功能:释放或者消耗一个信号量

        函数的头文件:#include <sys/types.h>
                                 #include <sys/ipc.h>
                                 #include <sys/sem.h>

        函数的原型:int semop(int semid, struct sembuf *sops, size_t nsops);

        函数的参数:int semid:信号量的 id
                             struct sembuf *sops:你要对信号量的操作是一个核心结构体

struct sembuf{
                    unsigned short      sem_num; //信号在信号集中的索引,0代表第一个信号,1代表第二个信号  (即信号量数组的下标)
                    short      sem_op;         //进行什么操作:①+1:V操作  释放一个信号量;②-1:P操作  消耗一个信号量
                    short      sem_flg;        //操作标志0 设置信号量的默认操作(表示申请不到信号量就阻塞)
                }

                         size_t nsops :你要操作的信号量个数,一般写1    
(进行操作信号量的个数,即sops结构变量的个数,需大于或等于1。最常见设置此值等于1,只完成对一个信号量的操作)             

        函数的返回值:成功返回 0                         失败返回 -1

  1 #include<stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <fcntl.h>
  5 #include<unistd.h>
  6 #include <sys/types.h>
  7 #include <sys/ipc.h>
  8 #include <sys/sem.h>
  9 int main()
 10 {
 11         struct sembuf myops;
 12         int pd;
 13         pd=fork();
 14         if(pd == 0)
 15         {
 16                 key_t keyid;
 17                 int semid;
 18                 keyid=ftok("/home/ldw",2);
 19                 semid=semget(keyid,1,IPC_CREAT|0644);
 20                 semctl(semid,0,SETVAL,2);
 21                 myops.sem_num=0;
 22                 myops.sem_op=-1;
 23                 myops.sem_flg=0;
 24                 semop(semid,&myops,1);
 25                 int i;
 26                 for(i=0;i<5;i++)
 27                 {
 28                         printf("i==%d\n",i);
 29                         sleep(1);
 30                 }
 31                 myops.sem_op=1;
 32                 semop(semid,&myops,1);
 33         }
 34         if(pd > 0)
 35         {
 36                 sleep(1);
 37                 int j;
 38                 key_t keyid;
 39                 int semid;
 40                 keyid=ftok("/home/ldw",2);
 41                 semid=semget(keyid,1,IPC_CREAT|0644);
 42                 myops.sem_num=0;
 43                 myops.sem_op=-1;
 44                 myops.sem_flg=0;
 45                 semop(semid,&myops,1);
 46                 for(j=0;j<5;j++)
 47                 {
 48                         printf("j==%d\n",j);
 49                         sleep(1);
 50                 }
 51                 myops.sem_op=1;
 52                 semop(semid,&myops,1);
 53         semctl(semid,0,IPC_RMID);
 54         }
 55         return 0;
 56 }
//i==0 j==0 i==1 j==1 i==2 j==2 i==3 j==3 i==4 j==4

三、消息队列

        消息队列才是最符合要求进程间的通讯

消息队列的特点:

                ①消息先进先出
                ②可以同时接收多条消息
                ③写消息的时候,你写的消息会暂存在消息队列;当有进程读消息的时候,读取的最先进队列的

消息队列的消息的分类:
        可以是 1类消息
        可以是 2类消息..........
比如现在有三个进程:
        A B C
        还有一个消息队列
        A往消息队列里写  1类消息
        B往消息队列写  2类消息
        C去消息队列里读 1类或者是2类消息
        C去消息队列里读  3类消息  会阻塞

1、创建或者打开一个消息队列  msgget

        函数功能:创建或者打开一个消息队列

        函数头文件:#include <sys/types.h>
                             #include <sys/ipc.h>
                            #include <sys/msg.h>

        函数原型:int msgget(key_t key, int msgflg);

        函数的参数:key_t key:键值
                             int msgflg:IPC_CREAT|0644

        函数的返回值:成功返回 消息队列的 id                失败返回  -1

  1 #include<stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/ipc.h>
  4 #include <sys/msg.h>
  5 int main()
  6 {
  7         int msqid;
  8         key_t keyid;
  9         keyid=ftok("/home/ldw",2);
 10         printf("keyid:%d\n",keyid);
 11         msqid=msgget(keyid,IPC_CREAT|0644);
 12         printf("msqid:%d\n",msqid);
 13         return 0;
 14 }
keyid:33619970
msqid:0

2、向消息队列发送一条消息  msgsnd

        函数功能:向消息队列发送一条消息,将消息发送到消息队列的末尾

        函数的头文件:#include <sys/types.h>
                                 #include <sys/ipc.h>
                                 #include <sys/msg.h>

        函数的原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

        函数的参数:int msqid:消息队列的 id
                             const void *msgp:消息结构体指针

struct msgbuf {
               long mtype;       /* message type, must be > 0 */消息的类型
               char mtext[1];    /* message data */要写的消息的正文
           };

                  size_t msgsz:消息的大小(<4k),不包括type。则 msgsz = sizeof(msgbuf) - sizeof(mtype)

                         msgflg:一般写 0      表示无法发送就阻塞(没有满足条件就阻塞当前进程)

        函数的返回值:成功返回 0                              失败返回 -1

  1 #include<stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/ipc.h>
  4 #include <sys/msg.h>
  5 #include<string.h>
  6 struct msgbuf{
  7         long mtype;
  8         char mtext[100];
  9         
 10 } mybuf;
 11 int main()
 12 {
 13         key_t keyid;
 14         int msgid;
 15         keyid=ftok("/home/ldw",2);
 16         msgid=msgget(keyid,IPC_CREAT|0644);
 17         mybuf.mtype=1;
 18         strcpy(mybuf.mtext,"hello");
 19         msgsnd(msgid,&mybuf,sizeof(mybuf)-sizeof(long),0);
 20         return 0;
 21 }

3、从消息队列获取一条消息  msgrcv

        函数功能:从消息队列读取一条数据

        函数头文件:#include <sys/types.h>
                             #include <sys/ipc.h>
                             #include <sys/msg.h>

        函数原型:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);

        函数的参数:int msqid:消息队列的 id
                             void *msgp:存放读取到的消息的位置

struct msgbuf {
               long mtype;       /* message type, must be > 0 */消息的类型
               char mtext[1];    /* message data */要读的消息的正文
           };

                             size_t msgsz:消息的大小,包括type  (否则段错误)
                             long msgtyp:接收消息的类型
                             int msgflg:0   表示读取不到就阻塞(调用阻塞直到条件满足为止)

        函数的返回值:成功返回 0                       失败返回 -1

  1 #include<stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/ipc.h>
  4 #include <sys/msg.h>
  5 #include<string.h>
  6 struct msgbuf{
  7         long mtype;
  8         char mtext[100];
  9 }mybuf;
 10 int main()
 11 {
 12         key_t keyid;
 13         char buf[120];
 14         int msgid;
 15         keyid=ftok("/home/ldw",2);
 16         msgid=msgget(keyid,IPC_CREAT|0644);
 17         msgrcv(msgid,buf,sizeof(mybuf),1,0);
 18         printf("buf=%s\n",(buf+8));
 19         msgctl(msgid,IPC_RMID,NULL);
 20         return 0;
 21 }
//buf=hello

4、删除一个消息队列  msgctl

        函数功能:删除一个消息队列

        函数头文件:#include <sys/types.h>
                             #include <sys/ipc.h>
                             #include <sys/msg.h>

        函数原型:int msgctl(int msqid, int cmd, struct msqid_ds *buf);

        函数的参数:int msqid:消息队列的 id
                              int cmd:IPC_RMID
                              struct msqid_ds *buf:NULL

        函数的返回值:成功返回  0                                       失败返回  -1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值