进程间通信

进程间通信IPC:

1.无名管道:半双工(单向)通信,有固定的读端和写端。

适用情况:通信的进程只有两个,且为亲缘进程(父子进程,或者间接继承关系的进程)

  • 当管道中没有数据可读后,读端的进程会被等待(阻塞)
  • 当进程写一个所有读端都被关闭的管道时,写端进程会被内核返回的SIGPIPE信号终止,如果不想被终止,则需要忽略、捕获、屏蔽该信号
  • 用两个管道才能实现双向通信

2.有名管道:FIFO 单向通信,

 

 

消息队列:

消息队列使用步骤:

  1. 使用msget函数创建新的消息队列,或者获取已经存在的消息队列,并返回唯一的标识消息队列的标识符(没事情ID),后续收发消息使用这个标识符李来实现。
  2. 使用msgsnd函数,(send的意思)利用消息队列标识符发送某编号的消息。
  3. 使用msgrcv函数,(receive的意思)利用消息队列标识符接受某编号的消息。
  4. 使用msgctl函数,(ctrl的意思) 利用消息队列标识符删除消息队列

多个进程间通信,只需要创建一个消息队列。为了保证消息队列的创建,最好让每个进程都包含创建消息队列的代码。谁先运行就由谁来创建。后运行的进程会直接使用已经创建好的消息队列。

如何验证消息队列是否被创建成功:

使用ipcs 命令查看  :

  • -a :显示 消息队列、共享内存、信号量的信息
  • -m:(memory)显示共享内存的信息
  • -q:   (queue)显示消息队列的信息
  • -s :     (semapaore)显示信号量的信息

使用ipcrm命令删除:

------删除共享内存

  • -M : 按照key值删除
    ipcrm -M key
  • -m:按照标识符删除
    ipcrm -m msgid

------删除消息队列

  • -Q:按照key值删除
  • -q:按照标识符删除

------删除信号量

  • -S:按照key值删除
  • -s:按照标识符删除

 

下面是用消息队列实现的 多进程网状通信的例子程序:

/*
本程序 用一个消息队列,实现多进程之间的网状通信
运行方式: 需要Linux操作系统环境
1.先打开一个终端窗口(后面称为TTY1),编译gcc message_queue.c -o message_queue
  运行 ./message_queue 1
  input your send message text:
  qqqqqqqqqqqqqqwwwwwwwwwww
  input snd_msgtype: 
  2
2.另外打开2个终端(后面称为TTY2 TTY3)
3. TTY2下运行 ./message_queue 2,将会看到 TTY1窗口发送来的  qqqqqqqqqqqqqqwwwwwwwwwww
*/

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <signal.h>


#define MSG_FILE "./msgfile"  //生成key 需要的文件路径
#define MSG_SIZE 1024         //指定消息内容大小

struct msgbuf   //固定的结构体,msgsnd 函数和 msgrcv函数 规定的消息格式
{
	long mtype;  //存放消息编号,必须 >0
	char mtext[MSG_SIZE];  //消息内容(消息正文)
};

void print_err(char *estr)
{
	perror(estr);
	exit(-1);
}


/*创建消息队列,或着获得消息队列id
返回值: msgid: 新创建的消息队列的id,或者已经存在的消息队列的id

*/
int creat_or_get_msgque(void)
{
	int msgid = -1;
	key_t key=-1;
	int fd=0;

	fd =open(MSG_FILE,O_RDWR|O_CREAT,0664);
	if(fd == -1) print_err("open fail");

	key=ftok(MSG_FILE, 'a');  //利用ftok函数获取 msgget函数的key值
	if(key == -1)
		print_err("open fail");

	msgid=msgget(key,0664|IPC_CREAT); //如果key值相同,则会返回已经存在的消息队列ID,否则会创建一个新的消息队列
	if(msgid == -1)
		print_err("msgget fail");

	return msgid;  
}

int msgid = -1;
void signal_fun(int signo) //捕获到信号后要执行的函数
{
	msgctl(msgid,IPC_RMID,NULL);
	exit(-1);
}
int main(int argc,char *argv[])
{
	pid_t pid=-1;
	long recv_msgtype =0; //指定 接收消息编号, 该进程只能读取,该消息编号里的类容
	if(argc!=2)
	{
		print_err("./message_queue recv_msgtpye\n");
		exit(-1);
	}
	recv_msgtype=atol(argv[1]);

	msgid =creat_or_get_msgque();
	
	pid=fork();
	if(pid<0)
		print_err("fork fail");
	if(pid>0) //发送消息
	{
		signal(SIGINT,signal_fun);
		struct msgbuf msg_buf={0};
		while(1)
		{
			bzero(&msg_buf,sizeof(msg_buf));  //清空消息队列
			//封装消息包
			scanf("%s",msg_buf.mtext);       //输入你要发送的消息
			printf("input snd_msgtype: \n"); 
			scanf("%ld",&msg_buf.mtype);    //输入 消息编号
			//发送消息
			msgsnd(msgid,&msg_buf,MSG_SIZE, 0);	
		}
	}
	else if(pid==0)// 接收消息
	{
		
		struct msgbuf msg_buf={0};
		int ret=0;
		while(1)
		{
			bzero(&msg_buf,sizeof(msg_buf));   //清空消息队列
			ret=msgrcv(msgid,&msg_buf,MSG_SIZE,recv_msgtype,0);
			if(ret>0)
			{
				printf("%s\n",msg_buf.mtext);
			}

		}
	}

}

 

共享内存:

共享内存使用步骤:

  1. 进程调用shmget函数创建新的或者已经存在的共享内存,shm是share memory的缩写
  2. 进程调用shmat函数,将物理内存映射到自己的进程空间
  3. shmdt函数,取消映射
  4. 调用shmctl函数释放开辟的物理内存空间

多个进程共享内存通信时,创建者只需要一个,一般是谁先运行谁创建。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值