IPC进程间通信

时间:2022-02-26 19:05:16

IPC进程间通信

进程间通信的几种方法:

1.信号函数sigqueue()

2.管道

3.信号

4.消息队列

5.共享内存:使多个进程能够访问同一个共享内存空间(最快的IPC形式)

6.信号量:主要作为进程间以及同一进程不同线程的同步手段

7.套接口:可用于不同机器间的进程通信

 

//*****************************************消息队列函数***************************************************
//2013.10.21.陈顺明
//int  msgget(key_t key, int msgflg)
//作用:用来创建和访问一个消息队列
//参数:
// key: 某个消息队列的名字
// msgflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
//     如果操作成功,msgget将返回一个非负整数,即该消息队列的标识码
//返回:如果失败,则返回“-1”

//int  msgctl(int msqid, int command, strcut msqid_ds *buf)
// 作用:消息队列的控制函数,与共享内存的控制函数很相似
// 参数:
// msqid: 由msgget函数返回的消息队列标识码; command:是将要采取的动作,(有三个可取值)IPC_RMID是删除队列
// 返回:如果操作成功,返回“0”;如果失败,则返回“-1”

// int  msgsnd(int msgid, const void *msg_ptr, size_t msg_sz,int msgflg);
// 作用:作用:把一条消息添加到消息队列里去
// 参数:
// msgid: 由msgget函数返回的消息队列标识码
// msg_ptr:是一个指针,指针指向准备发送的消息,
// msg_sz:是msg_ptr指向的消息长度,这个长度不能保存消息类型的那个“long int”长整型计算在内(计算大小不包含int type消息类型)
// msgflg:控制着当前消息队列满或到达系统上限时将要发生的事情
// 返回:操作成功,返回“0”,如果失败,则返回“-1”

//int  msgrcv(int msgid, void *msg_ptr, size_t msgsz, long int msgtype,int msgflg)
// 作用:是从一个消息队列里检索消息
// 参数:
// msgid: 由msgget函数返回的消息队列标识码
// msg_ptr:是一个指针,指针指向准备接收的消息,
// msgsz:是msg_ptr指向的消息长度,这个长度不能保存消息类型的那个“long int”长整型计算在内
// msgtype:它可以实现接收优先级的简单形式(设置类型type,只接收该类型的;如果设置成0,表示从第一个数据开始接收)
// msgflg:控制着队列中没有相应类型的消息可供接收时将要发生的事
// 返回:操作成功,返回实际放到接收缓冲区里去的字符个数,如果失败,则返回“-1”
//*****************************************消息队列函数***************************************************

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>

typedef struct Messege
{
 int type;
 char messege[1024];
}Messege_T;
typedef struct IntMsg
{
 int type;
 int data;
}IntMsg_T;


int main()
{
// int msgid = msgget((key_t)1234, IPC_CREAT | 0766); //创建ipc消息队列
//  int msgid = msgget((key_t)1234, 0);     //打开消息队列
//  printf("msgid is :  %d\n", msgid);
//  msgctl(msgid, IPC_RMID, NULL);      //删除消息队列

 //安全的创建方式::创建的时候先打开,判断是否存在消息队列,如果有,删除,最后创建
 int msgid = msgget((key_t)1234, 0);     //打开消息队列
 if (msgid > 0)
 {
  msgctl(msgid, IPC_RMID, NULL);     //判断是否存在要创建的消息队列,如果有,删除消息队列
 }
 msgid = msgget((key_t)1234, IPC_CREAT | 0766);  //创建ipc消息队列
 printf("msgid is :  %d\n", msgid);
 //把字符型内容添加到消息队列
 Messege_T msg;          
 memset(&msg, 0, sizeof(Messege_T));
 msg.type = 1;
 strcpy(msg.messege, "HElloWorld\n");
 msgsnd(msgid, &msg, sizeof(Messege_T)-sizeof(int), 0); 
 strcpy(msg.messege, "ChenShunming\n");   //再添加一条字符型内容
 msgsnd(msgid, &msg, sizeof(Messege_T)-sizeof(int), 0);
 //把int型内容添加到消息队列
 IntMsg_T intmsg;
 memset(&intmsg, 0, sizeof(IntMsg_T));
 intmsg.type = 2;
 intmsg.data = 100;
 msgsnd(msgid, &intmsg, sizeof(IntMsg_T)-sizeof(int), 0);
 
 //从消息队列里获取消息(消息队列的接收)
//  Messege_T rcvmsg;
//  memset(&rcvmsg, 0, sizeof(Messege_T));
//  msgrcv(msgid, &rcvmsg, sizeof(Messege_T)-sizeof(int), 1, 0);//这里的长度不算类型长度,后一个参数1为类型type
//  printf("Get messege data: %s\n", rcvmsg.messege);

 //msgtype如果设置成0,表示从第一个数据开始接收
 while(1)
 {
  Messege_T rcvmsg;
  memset(&rcvmsg, 0, sizeof(Messege_T));
  msgrcv(msgid, &rcvmsg, sizeof(Messege_T)-sizeof(int), 0, 0);//这里的长度不算类型长度,后一个参数1为类型type
  printf("Get messege data: %s\n", rcvmsg.messege);//打印的时候int类型的数据打印不出来。
 }

 

 return 0;
}

Linux里面shell命令ipcs查看ipc信息

[root@bogon ~]# ipcs

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status     
0x00000000 98304      root      600        393216     2          dest        
0x00000000 131073     root      600        393216     2          dest        
0x00000000 163842     root      600        393216     2          dest        
0x00000000 196611     root      600        393216     2          dest        
0x00000000 229380     root      600        393216     2          dest        
0x00000000 262149     root      600        393216     2          dest        
0x00000000 294918     root      600        393216     2          dest        
0x00000000 327687     root      600        393216     2          dest        
0x00000000 360456     root      600        393216     2          dest        

------ Semaphore Arrays --------
key        semid      owner      perms      nsems    
0x4d004237 0          root      600        8        

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages

 

//*****************************************共享内存(系统内核的内存)***************************************************
//2013.10.21.陈顺明
//int  shmget(key_t key,size_t size, int shmflg)
// 作用:用来创建共享内存
// 参数:
// key: 这个共享内存段的名字
// size: 需要共享的内存量
// shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
// 返回:如果共享内存创建成功,shmget将返回一个非负整数,即该段共享内存的标识码;如果失败,则返回“-1”

// void* shmat(int shm_id, const void *shm_addr, int shmflg)让系统内存给我们分配逻辑地址,让它指向共享内存的首地址
// 作用:共享内存段刚被创建的时候,任何进程还都不能访问它,为了建立对这个共享内存段的访问渠道,
//    必须由我们来把它连接到某个进程的地址空间,shmat函数就是用来完成这项工作的。
// 参数:
// shm_id: shmget返回的共享内存标识
// shm_addr:把共享内存连接到当前进程去的时候准备放置它的那个地址
// /shmaddr为0,核心自动选择一个地址(**一般把标志设置成0**)
// /shmaddr不为0且shmflg无SHM_RND标记,则以shmaddr为连接地址。
// /shmaddr不为0且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr - (shmaddr % SHMLBA)
// shmflg=SHM_RDONLY,表示连接操作用来只读共享内存
// shmflg:是一组按位OR(或)在一起的标志。它的两个可能取值是SHM_RND和SHM_RDONLY
// 返回:调用成功,返回一个指针,指针指向共享内存的第一个字节,如果失败,则返回“-1”

// int  shmctl(int shm_id, int command, struct shmid_ds *buf)
// 作用:共享内存的控制函数
// 参数:
// shm_id: 由shmget返回的共享内存标识码
// command:将要采取的动作(有三个可取值)  IPC_RMID删除
// buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
// 返回:操作成功,返回0,失败则返回-1

//int  shmdt(const void *shm_addr)
// 作用:把共享内存与当前进程脱离开,脱离共享内存并不等于删除它,只是当前进程不能再继续访问它而已
// 参数:shm_addr: 由shmat返回的地址指针
// 返回:操作成功,返回“0”,失败则返回“-1”
//*****************************************共享内存(系统内核的内存)***************************************************

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
int main()
{
 int shmid = shmget((key_t)0001, 0, 0);     //打开共享内存(后两个参数要设置成0)
 if (shmid > 0)
 {
  shmctl(shmid, IPC_RMID, NULL);      //如果存在共享内存,删除共享内存
 }
 shmid = shmget((key_t)0001, 1024, IPC_CREAT | 0766); //创建共享内存(要设置大小)
 printf("shmid is :%d\n", shmid);

 void *ptr = shmat(shmid, NULL, 0);      //给共享内存关联逻辑地址
 printf("ptr is: %p\n", ptr);       //打印逻辑地址
 memcpy(ptr, "HelloWorld!\n", strlen("HelloWorld!\n")); //给共享内存的地址拷贝内容

 char acBuf[1024] = {0};
 memcpy(acBuf, ptr, 1024);        //从共享内存里读取数据(拷贝数据)
 printf("Read Data is: %s\n", acBuf);

 shmdt(ptr);            //删除映射的逻辑地址
 shmctl(shmid, IPC_RMID, NULL);       //删除共享内存

 return 0;
}

 

//*********************************************信号量(semaphore)**********************************************
/*2013.10.22.陈顺明*/
// int  semget (key_t key,int num_sems,int sem_flag);
// 作用:创建一个新的信号量或者取得一个现有信号量的键字
// 参数:
// key: 是一个整数值,不相关的进程将通过这个值去访问同一个信号量
// num_sems:需要使用的信号量个数,它几乎总是取值为1
// sem_flags:是一组标志,其作用与open函数的各种标志很相似,它低端的九个位是该信号量的权限,其作用相当于文件的访问权限,可以与键值IPC_CREATE做按位的OR操作以创建一个新的信号量
// 返回:成功时将返回一个正数值,它就是其他信号量函数要用到的那个标识码,如果失败,将返回-1

// int semctl(int sem_id,int sem_num,int command,…)(*具体 man semctl)
// 作用:允许我们直接控制信号量的信息
// 参数:
// sem_id: 是由semget函数返回的一个信号量标识码
// sem_num: 信号量的编号,如果在工作中需要使用到成组的信号量,就要用到这个编号;(信号量的下标)
   //它一般取值为0,表示这是第一个也是唯一的信号量
// comman:将要采取的操作动作
// 返回:如果还有第四个参数,那它将是一个“union semun”复合结构(最后有备注)

//*********************************************信号量(semaphore)**********************************************

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

union semun     //系统没有这个联合体,要自己定义
{
 int              val;    /* Value for SETVAL */
 struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
 unsigned short  *array;  /* Array for GETALL, SETALL */
 struct seminfo  *__buf;  /* Buffer for IPC_INFO
        (Linux-specific) */
};
int sem_create(key_t key, int num_sems)    //创建信号量
{
 int semid = semget(key, num_sems, IPC_CREAT |0766);
 if (semid < 0)
 {
  perror("Semaphore creat error!\n");
 }
 return semid;
}
int sem_open(key_t key, int num_sems)    //打开信号量
{
 int semid = semget(key, num_sems, 0);
 if (semid < 0)
 {
  perror("Semaphore open error!\n");
 }
 return semid;
}
int sem_setval(int semid, int sem_num, int value) //设置信号量
{
 union semun arg;
 arg.val = value;
 int ret = semctl(semid, sem_num, SETVAL, arg);
 if (ret < 0)
 {
  perror("Semaphore set value error!\n");
 }
 return ret;
}
int sem_getval(int semid, int sem_num)    //获取信号量
{
 int ret = semctl(semid, sem_num, GETVAL);
  if (ret < 0)
  {
   perror("Semaphore get value error!\n");
  }
 return ret;
}
int sem_setall(int semid, int sem_num, unsigned short  *array)//设置所有信号量
{
 union semun arg;
 arg.array = array;
 int ret = semctl(semid, sem_num, SETALL, arg);//sem_num为信号量下标从下标位置开始设置所有信号量(设置起始位置)
 if (ret < 0)
 {
  perror("Semaphore setall value error!\n");
 }
 return ret;
}
int sem_getall(int semid, int sem_num, unsigned short  *array) //获取所有信号量值
{
 union semun arg;
 arg.array = array;
 int ret = semctl(semid, sem_num, GETALL, arg);
 if (ret < 0)
 {
  perror("Semaphore setall value error!\n");
 }
 return ret;
}
int sem_distory(int semid)          //删除信号量
{
 int ret = semctl(semid, 0, IPC_RMID);
 if (ret < 0)
 {
  perror("Semaphore delet error!\n");
 }
 return ret;
}

int main()
{
 int semid = sem_create(ftok(".", getpid()), 5);//key_t ftok(const char *pathname, int proj_id) 根据路径名和ID生成随机的key值
 sem_setval(semid, 0, 100);    //设置下标为0的信号量值为100
 int value = sem_getval(semid, 0);  //获取下标为0的信号量的值
 printf("value : %d\n", value);   //打印获取到下标为0的信号量的值

 unsigned short array[5];
 int i = 0;
 for (i = 0; i < 5; i++)     //初始化一个数组
 {
  array[i] = i;
 }
 sem_setall(semid, 0, array);   //从0位置开始设置所有信号量
 for (i = 0; i < 5; i++)     //打印所有信号量的值
 {
  printf("get value: %d\n", sem_getval(semid, i));
 }

 unsigned short newarray[5];
 sem_getall(semid, 0, newarray);   //获取到的所有信号量值给newarray数组
 for (i = 0; i < 5; i++)     //打印获取到的所有信号量的值
 {
  printf("get all value: %d\n", newarray[i]);
 }

 sem_distory(semid);      //删除信号量
 return 0;
}

 

/******************************************PV锁操作********************************************************************

//*********************************************信号量pv操作(semaphore)**********************************************
/*2013.10.22.陈顺明*/
//信号量操作封装
//PV锁让只能一个进程操作
//*********************************************信号量pv操作(semaphore)**********************************************

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

union semun       //系统没有这个联合体,要自己定义
{
 int     val;     /* Value for SETVAL */
 struct semid_ds  *buf;    /* Buffer for IPC_STAT, IPC_SET */
 unsigned short  *array;  /* Array for GETALL, SETALL */
 struct seminfo  *__buf;  /* Buffer for IPC_INFO*/
};
int sem_create(key_t key, int num_sems)       //创建信号量
{
 int semid = semget(key, num_sems, IPC_CREAT |0766);
 if (semid < 0)
 {
  perror("Semaphore creat error!\n");
 }
 return semid;
}
int sem_open(key_t key, int num_sems)       //打开信号量
{
 int semid = semget(key, num_sems, 0);
 if (semid < 0)
 {
  perror("Semaphore open error!\n");
 }
 return semid;
}
int sem_setval(int semid, int sem_num, int value)    //设置信号量
{
 union semun arg;
 arg.val = value;
 int ret = semctl(semid, sem_num, SETVAL, arg);
 if (ret < 0)
 {
  perror("Semaphore set value error!\n");
 }
 return ret;
}
int sem_getval(int semid, int sem_num)       //获取信号量
{
 int ret = semctl(semid, sem_num, GETVAL);
 if (ret < 0)
 {
  perror("Semaphore get value error!\n");
 }
 return ret;
}
int sem_setall(int semid, int sem_num, unsigned short  *array) //设置所有信号量
{
 union semun arg;
 arg.array = array;
 int ret = semctl(semid, sem_num, SETALL, arg);    //sem_num为信号量下标从下标位置开始设置所有信号量(设置起始位置)
 if (ret < 0)
 {
  perror("Semaphore setall value error!\n");
 }
 return ret;
}
int sem_getall(int semid, int sem_num, unsigned short  *array) //获取所有信号量值
{
 union semun arg;
 arg.array = array;
 int ret = semctl(semid, sem_num, GETALL, arg);
 if (ret < 0)
 {
  perror("Semaphore setall value error!\n");
 }
 return ret;
}
int sem_distory(int semid)          //删除信号量
{
 int ret = semctl(semid, 0, IPC_RMID);
 if (ret < 0)
 {
  perror("Semaphore delet error!\n");
 }
 return ret;
}
int sem_p(int semid, int semnum)        //信号量P操作
{
 struct sembuf buf = {semnum, -1, 0};
 int ret = semop(semid, &buf, 1);       //最后一个参数1(struct sembuf 数组就一个,如果是buf[2],参数就是2)
 if (ret < 0)
 {
  perror("Semaphore p operate error!\n");
 }
 return ret;
}
int sem_v(int semid, int semnum)        //信号量V操作
{
 struct sembuf buf = {semnum, 1, 0};
 int ret = semop(semid, &buf, 1);
 if (ret < 0)
 {
  perror("Semaphore V operate error!\n");
 }
 return ret;
}
//**********************************************PV锁让只能一个进程操作****************************************
int main()
{
 int semid = sem_create((key_t)3333, 1);     //创建信号量,有1组信号量
 sem_setval(semid, 0, 1);        //设置下标为0的信号量值为1
 int pid = fork();
 if (pid > 0)
 {
  while(1)
  {
   sem_p(semid, 0);        //执行P操作,信号量-1
   printf("Parent++++++++++++++++\n");
   sleep(3);
   sem_v(semid, 0);        //执行V操作,信号量+1
  }
 }
 if (pid == 0)
 {
  while(1)
  {
   sem_p(semid, 0);        //执行P操作,信号量-1 
   printf("Child-----------------\n");
   sleep(3);
   sem_v(semid, 0);        //执行V操作,信号量+1
  }
  
 }
 else
 {
  perror("Fork error!\n");
 }
       
 return 0;
}

 

 

//*********************************************信号量pv操作(semaphore)**********************************************
/*2013.10.22.陈顺明*/
// int semop(int semid, struct sembuf *sops, unsigned nsops);
// 作用:改变信号量的键值,Semop调用的一切动作都是一次性完成的,这是为了避免出现因使用了多个信号量而可能发生的竞争现象
// sem_id: 是该信号量的标识码,也就是semget函数的返回值
// sem_ops:是个指向一个结构数值的指针  
//unsigned nsops:前一个参数结构体数组的个数
//*********************************************信号量pv操作(semaphore)**********************************************

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

union semun       //系统没有这个联合体,要自己定义
{
 int     val;     /* Value for SETVAL */
 struct semid_ds  *buf;    /* Buffer for IPC_STAT, IPC_SET */
 unsigned short  *array;  /* Array for GETALL, SETALL */
 struct seminfo  *__buf;  /* Buffer for IPC_INFO*/
};
int sem_create(key_t key, int num_sems)       //创建信号量
{
 int semid = semget(key, num_sems, IPC_CREAT |0766);
 if (semid < 0)
 {
  perror("Semaphore creat error!\n");
 }
 return semid;
}
int sem_open(key_t key, int num_sems)       //打开信号量
{
 int semid = semget(key, num_sems, 0);
 if (semid < 0)
 {
  perror("Semaphore open error!\n");
 }
 return semid;
}
int sem_setval(int semid, int sem_num, int value)    //设置信号量
{
 union semun arg;
 arg.val = value;
 int ret = semctl(semid, sem_num, SETVAL, arg);
 if (ret < 0)
 {
  perror("Semaphore set value error!\n");
 }
 return ret;
}
int sem_getval(int semid, int sem_num)       //获取信号量
{
 int ret = semctl(semid, sem_num, GETVAL);
 if (ret < 0)
 {
  perror("Semaphore get value error!\n");
 }
 return ret;
}
int sem_setall(int semid, int sem_num, unsigned short  *array) //设置所有信号量
{
 union semun arg;
 arg.array = array;
 int ret = semctl(semid, sem_num, SETALL, arg);    //sem_num为信号量下标从下标位置开始设置所有信号量(设置起始位置)
 if (ret < 0)
 {
  perror("Semaphore setall value error!\n");
 }
 return ret;
}
int sem_getall(int semid, int sem_num, unsigned short  *array) //获取所有信号量值
{
 union semun arg;
 arg.array = array;
 int ret = semctl(semid, sem_num, GETALL, arg);
 if (ret < 0)
 {
  perror("Semaphore setall value error!\n");
 }
 return ret;
}
int sem_distory(int semid)          //删除信号量
{
 int ret = semctl(semid, 0, IPC_RMID);
 if (ret < 0)
 {
  perror("Semaphore delet error!\n");
 }
 return ret;
}
int sem_p(int semid, int semnum)        //信号量P操作
{
 struct sembuf buf = {semnum, -1, 0};
 int ret = semop(semid, &buf, 1);       //最后一个参数1(struct sembuf 数组就一个,如果是buf[2],参数就是2)
 if (ret < 0)
 {
  perror("Semaphore p operate error!\n");
 }
 return ret;
}
int sem_v(int semid, int semnum)        //信号量V操作
{
 struct sembuf buf = {semnum, 1, 0};
 int ret = semop(semid, &buf, 1);
 if (ret < 0)
 {
  perror("Semaphore V operate error!\n");
 }
 return ret;
}
//************************************************PV操作的实现******************************************
// int main()
// {
//  int semid = sem_create((key_t)3333, 5);   //创建信号量,有5组信号量
//  sem_setval(semid, 0, 100);      //设置下标为0的信号量值为0
//
//  sem_v(semid, 0);        //执行V操作,信号量+1
//  int value = sem_getval(semid, 0);    //获取信号量值
//  printf("value : %d\n", value);     //打印信号量结果value :101
//
//  sem_p(semid, 0);        //执行P操作,信号量-1
//  value = sem_getval(semid, 0);     //获取信号量值
//  printf("value : %d\n", value);     //打印信号量结果value :100
//
//
//  sem_distory(semid);        //删除信号量
//  return 0;
// }

//*****************************************信号量为0,P操作,进程进入堵塞状态****************************
int main()
{
 int semid = sem_create((key_t)3333, 5);   //创建信号量,有5组信号量
 sem_setval(semid, 0, 0);      //设置下标为0的信号量值为0
 
 sem_p(semid, 0);        //执行P操作,信号量-1(执行的时候进程堵塞)
 int value = sem_getval(semid, 0);     
 printf("value : %d\n", value);     
 
 
 sem_distory(semid);        
 return 0;
}