进程间通信之消息队列

消息队列

  • 一. 什么是消息队列
  • 二. 消息队列有关函数
    • 1.获取key - ftok
    • 2.创建消息队列 - msgget
    • 3.发送消息 - msgsnd
    • 4.接收消息 - msgrcv
    • 5.删除消息队列 - msgctl
  • 三. 实例
    • 注意:

一. 什么是消息队列

消息队列独立于发送消息的进程和接收消息的进程,消息队列是消息的链表,存放在内核中并由消息队列标识符标识。
每个消息队列都有一个标识,只有持有这个标识的进程才可以去里面拿消息

生命周期随内核,消息队列会一直存在,需要我们调用接口删除或使用命令删除

进程间通信之消息队列_第1张图片

二. 消息队列有关函数

1.获取key - ftok

功能 : 获取一个独一无二的key,作为传给共享内存的一个参数

#include 
#include 

key_t ftok(const char *pathname, int proj_id);
key_t key = ftok("./read", 'a');
pathname:
		提前创建的可访问文件的文件名,可以随意写
proj_id:
		任意一个字符

返回值:
		成功则返回生成的key值,失败则返回-1

2.创建消息队列 - msgget

功能 : 创建消息队列

#include 
#include 
#include 

int msgget(key_t key, int msgflg);
int msgget(key_t key,int msgf1g);
key:
		ftok得到的key值或者IPC_PRIVATE(创建私有的消息队列)
msgf1g:
		IPC_CREAT | 0664
返回值:
		成功: 返回消息队列id
		失败: 返回-1;

3.发送消息 - msgsnd

功能 : 发送消息

#include 
#include 
#include 

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
int msgsnd(int msqid,const void *msgp,size_t msgsz,int msgf1g);
smqid:
		创建或者打开消息队列得到的id号
msgp:
		是一个结构体指针,类型为struct msgbuf *,表示为发送消息结构体的首地址
		struct msgbuf {
               long mtype;       /* message type, must be > 0 */     类型
               char mtext[1];    /* message data */          	  	 数据
        };

msgsz:
		消息正文内容的大小
msgf1g:
		0:阻塞方式发送
		IPC_NOWAIT:以非阻塞方式发送
返回值:	
		成功:0
		失败:-1

例如:

typedef struct msgbuf//定义消息结构体
{
	1ong mtype;
	char mtext[1024];
}MSG;
#define LEN (sizeof(MSG)-sizeof(long)) 		//计算消息正文内容大小

MSG msg;	//定义消息结构体变量

while(1)
{
	msg.mtype = 100;	//封装消息类型
	fgets(msg.mtext,1024,stdin);	//输入消息正文
	msg.mtext[str1en(msg.mtext)-1] = '\O';
	msgsnd(id,&msg,LEN,O);	//发送消息
}

4.接收消息 - msgrcv

功能 : 接收数据

#include 
#include 
#include 

ssize_t msgrcv(int msgid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
ssize_t msgrcv(int msgid, void *msgp,size_t msgsz,long msgtyp, long msgflg);

msgid:
		创建或者打开消息队列得到的id号
msgp: 
		发送消息结构体的首地址
msgsz:
		消息正文的长度 sizeof(msg) - sizeof(long)
msgtyp:
		消息的类型
msgflg:
		0:阻塞方式发送
		IPC_NOWAIT:以非阻塞方式发送
返回值:	
		成功:0
		失败:-1

5.删除消息队列 - msgctl

#include 
#include 
#include 

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
int msgct1(int msgid, int cmd,struct msqid_ds *buf);功能:控制函数
参数:
msgid: 
		创建或者打开消息队列得到的id号
cmd: 
		IPC_STAT:获取消息队列信息,将信息存储在第三个参数地址当中
        IPC_SET:设置消息队列,将第三个参数的地址的消息队列内容,设置到内核消息队列当中
        IPC_RMID:删除消息队列
buf: 
		如果第二个参数为 IPC_RMID,该值可以为NULL
返回值:
		成功: 0
		失败: -1

三. 实例

子进程发送消息,父进程接收消息
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

struct msgbuf{
    long mtype;
    char mtext[50];
};

int main(int argc, char *argv[])
{ 
    //1.获取key
    key_t key = ftok("/",'a');
    if(key == -1)
    {
        perror("ftok");
        return -1;
    }

    //2.创建消息队列
    int msgid = msgget(key,IPC_CREAT | 0664);
    if(msgid == -1)
    {
        perror("msgget");
        return -1;
    }

    // 进程间通信
    pid_t pid = fork();
    if(pid < 0)
    {
        perror("fork");
        //如果创建进程失败,删除消息队列
        goto xxx;
    }
    else if(pid == 0)
    {
        struct msgbuf buf;
        while(1)
        {
            /******发送消息******/
            //初始化结构体
            buf.mtype = 10;
            gets(buf.mtext);
            msgsnd(msgid,&buf,sizeof(buf) - sizeof(long),0);
        }
    }
    else
    {
        struct msgbuf buf;
        /******收消息******/
        while(1)
        {
            msgrcv(msgid,&buf,sizeof(buf) - sizeof(long),10,0);
            printf("massge: %s\n",buf.mtext);
            memset(buf.mtext,0,sizeof(buf.mtext));
        }
    }

    //删除消息队列
    int ret = msgctl(msgid, IPC_RMID, NULL);
    if(ret == -1)
    {
        perror("msgctl");
        goto xxx;
    }

xxx:
    sleep(2);
    char str[100] = {0};
    //使用命令删除消息队列
    sprintf(str, "ipcrm -q %d", msgid);
    system(str);
    system("ipcs -q");
    return 0;
} 

注意:

	ipcs -q:      	   //查询显示当前系统的消息队列
	ipcrm -q msgid:     //删除某个消息队列

在这里插入图片描述
在这里插入图片描述

你可能感兴趣的:(c语言,开发语言,消息队列)