Linux进程间通信——消息队列

消息队列

顾名思义,消息队列就是一些消息的列表。用户可以在消息队列中添加消息或者读消息等。

消息队列的实现包括创建或打开消息队列,添加消息,读取消息,和控制消息队列这4种操作。消息队列是内核地址空间中的内部链表,通过Linux内核在个进程间传递消息,消息顺序地发送到消息队列中,并且以几种不同的方式从队列中获取,每一个消息队列可以用IPC标识符唯一的进行标识,内内核中的消息队列是通过IPC的标识符来区别的,不同的消息队列之间是相互独立的,每个消息队列中的消息有构成一个独立的链表。

数据结构
msgbuf:
struct msgbuf{	
long   	mytpe;	//消息类型,该结构必须从这域开始
char	mtex[1];	//消息正文
}
相关函数
msgget():创建或打开消息队列
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
	key:消息队列的键值,多个进程可以通过它访问同一个消息队列,其中有个特殊的值
	IPC_PRIVATE。它用于创建当前进程的私有消息队列
	msgflg:权限标识位
	
	成功返回0;失败返回-1。
msgsnd():添加消息
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, struct msgbuf *msgp, int msgsz, int msgflg);
	msqid:消息队列的id
	msgbuf:消息结构指针
	msgsz:消息正文的字节数(不包括消息类型指针变量)
	msgflg:用于控制当前消息队列满或队列消息到达系统范围的限制时将要发生的事情。
			IPC_NOWAIT 若消息无法立即发送(比如消息队列已满),函数会立即返回
			0  msgsnd 调用阻塞直到发送成功为止
	
	成功返回0;失败返回-1
msgrcv():从消息队列中获取一个相应类型的消息并删除消息
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgrcv(int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg);
	msqid:消息队列的id
	msgp:消息缓冲区
	msgsz:消息正文的字节数
	msgtyp:
			0:接受消息队列中第一个消息
			大于0:接收消息队列中第一个类型为msgtyp的消息
			小于0:接收消息队列中第一个类型值不小于msgtyp绝对值且类型值又最小的消息
	msgflg:
			MSG_NOERROR:若返回消息比msgsz字节多,则消息就会截短到msgz字节,且不通知
			消息发送进程
			IPC_NOWAIT:若消息队列中并没有相应的消息类型
			0:表示msgsnd()调用阻塞直到接收到一条相应类型的消息为止
 

    成功返回0;失败返回-1

msgctl():控制消息队列使用

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
	msqid:消息队列的id
	cmd:命令参数
			IPC_STAT:读取消息队列的数据结构msqid_ds,并将其存在buf指定的地址中
			IPC_SET:设置消息队列的数据结构msgqid_ds中的ipc_perm域(IPC操作权限描述结构)
			值取自buf参数
			IPC_RMID:从系统内核中删除消息队列
	buf:描述消息队列的msqid_id 结构类型变量

msqid_ds:内核数据结构。

在这里插入图片描述
Linux内核中,每个消息队列都维护一个结构体,此结构体保存着消息队列当前状态信息,该结构体在头文件linux/msg.h中定义。

struct ipc_perm{
key_t key;
uid_t uid;
gid_t gid;
.......
};
	 
	成功返回0;失败返回-1
实例
三人抢消息制的聊天 head.h
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<unistd.h>
#include<errno.h>
#include <pthread.h>


#define BUF_SIZE 1024
#define err()    perror("%s",strerror(errno));exit(0)

struct msgbuf{	
long   	id;	//消息类型,该结构必须从这域开始
char	buf[BUF_SIZE];	//消息正文
};

struct member
{
	int pid;
	long id;
};
extern int create_msg_pid(char* path);
extern void msg_print(struct msgbuf *msg,int id);
extern void *Msg_read(void *arg);
extern void *Msg_write(void *arg);

oper.c

#include"head.h"
int create_msg_pid(char* path)
{
	key_t key=ftok(path,'a');
    if(key==-1)
    {
    	perror("key create is error");
    	exit(0);
    }
    int pid=msgget(key,IPC_CREAT|0666);
    if(pid==-1)
    {
    	perror("mesgget is error");
    	exit(0);
    }
    return pid;
}

void msg_print(struct msgbuf *msg)
{
	fflush(stdout);
    printf("%s",msg->buf);
    return ;
}

void *Msg_read(void *arg)
{
    struct member *tm;
    tm=(struct member *)arg;
    struct msgbuf msg;
    while(1)
    {
    	if(msgrcv(tm->pid,&msg,BUF_SIZE,tm->id,0)==-1)
    	{
    		error();
    	}
    	msg_print(&msg);
    }
	return NULL;
}

void Name_sign(char*buf1,char *buf2, int id)
{
	switch(id)
	{
		case 1:{strcpy(buf1,&"a");break;}
		case 2:{strcpy(buf1,&"b");break;}
		case 3:{strcpy(buf1,&"c");break;}
	}
	strcat(buf1,&" say to you:");
	int tt=0;
	while(buf2[tt]!='>'){++tt;}
	strcat(buf1,buf2+tt+1);
   return ;
}

void *Msg_write(void *arg)
{
	struct member *tm;
    tm=(struct member *)arg;
    struct msgbuf msg;
    char buf[BUF_SIZE];
    while(1)
    {
    	fflush(stdin);
    	bzero(msg.buf,sizeof(msg.buf));
    	fgets(buf,BUF_SIZE,stdin);
    	int tt=0;
    	while(buf[tt]==' '){++tt;}
    	if(buf[tt]=='a')       {msg.id=1;}
    	else if(buf[tt]=='b')  {msg.id=2;}
    	else if(buf[tt]=='c')  {msg.id=3;}
    	else
    	{
    		puts("dont have this people please try again");
    		continue;
    	}
        Name_sign(msg.buf,buf,tm->id);
    	if(msgsnd(tm->pid,&msg,BUF_SIZE,0)==-1)
    	{
    		error();
    	}
    	if(strcmp("quit",msg.buf)==0)
    	{
    		Msg_destroy(tm->pid); 
            exit(0);
    	}
    }
	return NULL;
}

void Msg_destroy(int pid)
{
	if(msgctl(pid,IPC_RMID,NULL)<0)
	{
		error();
		exit(0);
	}
	return;
}

a.c

#include"head.h"

int main(int argc, char const *argv[])
{
	struct member wir,rea;
    wir.pid=rea.pid=create_msg_pid(".");
    wir.id=rea.id=1;
    pthread_t read;
    pthread_t writ;
    puts("if you want send a message to other people please \n Follow the format below:");
    puts("(name who that you to say - a integer)->(message)");
    if(pthread_create(&read,0,Msg_read,(void*)&rea)==-1)
    {
        error();
    }
    if(pthread_create(&writ,0,Msg_write,(void*)&wir)==-1)
    {
    	error();

    }
     pthread_join(read,0);
     pthread_join(writ,0);
	return 0;
}

//b与c的跟a类似

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值