进程通信(消息队列、管道通信)

推荐一篇介绍进程通信的概论:(https://www.jianshu.com/p/c1015f5ffa74)

1消息队列

推荐阅读(https://blog.csdn.net/yang_yulei/article/details/19772649)
消息队列的创建与读写ftok,msgget,msgsnd,msgrcv,指令ipcs,ipcrm 查看,删除队列
消息队列函数(msgget、msgctl、msgsnd、msgrcv)及其范例
消息队列是存放在内核中的消息链表,每个消息队列由消息队列标识符表示。对于系统中的每个消息队列,内核维护一个定义在sys/msg.h头文件中的信息结构:
struct msqid_ds {
struct ipc_perm msg_perm ;
struct msg* msg_first ; //指向队列中的第一个消息
struct msg* msg_last ; //指向队列中的最后一个消息

} ;

消息队列中的几个重要函数:
1、int msgget (key_t key, int oflag) ;
返回值是一个整数标识符,其他三个msg函数就用它来指代该队列。它是基于指定的key产生的,而key既可以是ftok的返回值,也可以是常值IPC_PRIVATE。
oflag是读写权限的组合(用于打开时)。它还可以是IPC_CREATE或IPC_CREATE | IPC_EXCL(用于创建时)。

2、*int msgsnd (int msqid, const void ptr, size_t length, int flag) ;
其中msqid是由msgget返回的标识符。ptr是一个结构指针,该结构具有如下模板(我们需要按这个模板自己定义结构体)

struct mymesg {
long mtype ; //消息类型(大于0)
char mtext[512] ; //消息数据
} ;
//结构体的名字和其中变量名都由我们自己确定,我们只要按照这个模板定义即可。
消息数据mtext中,任何形式的数据都是允许的,无论是二进制数据还是文本,内核根本不解释消息数据的内容。(我们可以在消息的数据部分 再分割一部分 根据需要定义自己的通信协议)
参数length指定了待发送消息数据部分的长度。
参数flag的值可以指定为IPC_NOWAIT。这类似于文件IO的非阻塞IO标志。若消息队列已满,则指定IPC_NOWAIT使得msgsnd立即出错返回EAGAIN。
如果没有指定IPC_NOWAIT,则进程阻塞直到下述情况出现为止:①有空间可以容纳要发送的消息 ②从系统中删除了此队列(返回EIDRM“标识符被删除”)③捕捉到一个信号,并从信号处理程序返回(返回EINTR)。

3、size_t msgrcv (int msqid, void ptr, size_t length, long type, int flag) ;*
参数ptr指定所接收消息的存放位置。参数length指定了数据部分大小(只想要多长的数据)
参数type指定希望从队列中读出什么样的消息。
type == 0 返回队列中的第一个消息
type > 0 返回队列中消息类型为type的第一个消息
type < 0 返回队列中消息类型值小于或等于type绝对值的消息,如果这种消息有若干个。则取类型值最小的消息。
(如果一个消息队列由多个客户进程和一个服务器进程使用,那么type字段可以用来包含客户进程的进程ID)
参数flag可以指定为IPC_NOWAIT,使操作不阻塞。

4、int msgctl (int msqid, in cmd, struct msqid_ds * buff) ;
参数cmd说明对由msqid指定的队列要执行的命令:
IPC_STAT :取此队列的msqid_ds结构,并将它存放在buf指向的结构中。
IPC_SET :按由buf指向结构中的值,设置与此队列相关结构中的字段。
IPC_RMID:从系统中删除该消息队列以及仍在该队列中的所有数据。
(这三条命令也可用于信号量和共享存储)

c实现如下:

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/ipc.h> //包含ftok()
#include <sys/msg.h>
#include <sys/types.h> 
#include <error.h> 
#include<unistd.h>
#include<string.h>
#define BUF_SIZE 128 
struct mymsg { 
	long mtype;
	char mtext[BUF_SIZE];
}; 

void send_msg(int msgid,struct mymsg msgbuf); 
void receive_msg(int msgid,struct mymsg *qbuf,long type); 
void del_msg(int msgid); 

int get_key() {
	int key=ftok(".",'s');
	return key;
}

int getId(){

	int msgid=0;
	msgid=msgget(0x20180326,IPC_CREAT|IPC_EXEL0666);
	printf("msqid value:%d\n",x);
	return msgid;
}

int main() {
	struct mymsg msgbuf;
	key_t key;
	key=get_key();
	if(key<0) {
		perror("get key error");
		exit(1);
	}
	int msgid=getId();
	if(msgid<0) {
		perror("msgget error");
		exit(1);
	} printf("get msg success\n");
	while(1){
		send_msg(msgid,msgbuf);
		sleep(1);
		receive_msg(msgid,&msgbuf,1);
		sleep(5);
	}
	del_msg(msgid);
}

void send_msg(int msgid,struct mymsg msgbuf) 
{	
	printf("\nsending.....\n"); 
	//fgets(msgbuf.mtext,BUF_SIZE,stdin);
	strcpy(msgbuf.mtext,"hello");
	msgbuf.mtype=1;
	if(msgsnd(msgid,(void *)&msgbuf,sizeof(msgbuf.mtext),1)==-1) 
	{ 
		perror("send msg error"); 
		exit(1); 
	} printf("send msg success\n"); 
} 

void receive_msg(int msgid,struct mymsg *qbuf,long type) 
{ 
	printf("recving.....\n"); 
	if(msgrcv(msgid,qbuf, BUF_SIZE,type,IPC_NOWAIT)==-1) 
	{ 
		perror("recv msg error"); 
		exit(1); 
	} 
	else 
		printf("Type:%ld,Text:%s\n",qbuf->mtype,qbuf->mtext); 
} 

void del_msg(int msgid) { 
	if(msgctl(msgid,IPC_RMID,0)==-1) { 
		perror("rm msg error"); exit(1); 
	} 
}

注:以上代码只是消息队列功能的演示,并没有实现多进程功能,只需将发送和接收部分放到不同进程即可。

2、管道通信

推荐阅读管道通信的详细解释(http://blog.chinaunix.net/uid-26833883-id-3227144.html)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值