多进程间通信学习之消息队列

  • Linux系统下的IPC进程间通信的常用的命令:
  • 一、查看本系统下的消息队列、共享内存段、信号量数组:
  • ipcs
  • 1、若要单独查看消息队列ipcs -q
  • 2、若要单独查看共享内存段ipcs -m
  • 3、若要单独查看信号量数组ipcs -s
  • 二、删除本系统下的特定的消息队列、共享内存段、信号量数组:
  • 1、若要单独删除消息队列ipcrm -q msqid
  • 2、若要单独删除共享内存段ipcrm -m shmid
  • 3、若要单独删除信号量数组ipcrm -s semid
  • IPC进程间通信键值的获取(ftok函数):
	#include 
	#include 
	key_t ftok(const char *pathname, int proj_id);
	/*
		参数:
		
		    	pathname:		路径和文件名(必须是一个已存在的)
		    	proj_id:		填充的是任意一个字符
		
		返回值:
		
		    	成功  	键值
		    	失败  	-1  	重置错误码 
	*/
  • 示例代码:
	#include 
	#include 
	#include 
	
	#include 
	#include 
	#include 
	
	int main(int argc, char const *argv[])
	{
	    key_t key = ftok("/home/linux/work/MSG", 0x1234);
	
	    if(-1 == key)
	    {
	        perror("ftok error");
	        exit(1);
	    }
	
	    printf("key = %x\n",key);
	    struct stat lk;
	    stat("/home/linux/work/MSG",&lk);
	    printf("proj_id=%x,dev = %lx,inode=%lx\n",0x1234,lk.st_dev,lk.st_ino);
	
	    return 0;
	}


  • 运行结果:
	key = 34011052
	proj_id=1234,dev = 801,inode=2a1052
  • 总结:键值key = proj_id(低8位)+dev(低8位)+inode(低16位)

  • 消息队列:

  • 1、基于内核实现,必须在内核空间创建消息队列

  • 2、消息队列中的消息类型正文组成;

  • 3、消息队列的默认大小为16KB

  • 运行过程:

  • 1、进程1将消息写入到消息队列,进程2根据消息的类型从消息队列中取得对应的消息

  • 2、进程1向消息队列中发送消息,可以采用阻塞或者非阻塞的方式;

  • 3、进程2从消息队列中收取消息,也可以采用阻塞或者非阻塞的方式;

  • 常用的接口函数:

  • msgget函数:

  • 功能:创建或者获取一个消息队列;

	#include 
	#include 
	#include 
	
	int msgget(key_t key, int msgflg);
	/*
		参数:
		    	key:	键值
		
		        	key 	通过ftok获取的
		
		        	IPC_PRIVATE 表示只有亲缘进程间能只用
		
		    	msgflg:消息队列的标志位
		
		        	IPC_CREAT|0666  或者  IPC_CREAT|IPC_EXCL|0666 
		
		返回值:
		
		    	成功 消息队列的id
		
		    	失败 -1 重置错误码
	*/
  • msgsnd函数:
  • 功能:向消息队列中写入一条消息;
	int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
	/*
		参数:
	
	    	msqid:消息队列的id
	
	    	msgp: 要写入的数据的首地址
	
	    	msgsz:消息正文的大小
	
	    	msgflg:标志位 0 阻塞发送  IPC_NOWAIT 非阻塞发送
	
		返回值:
	    		成功 0
	
	    		失败 -1  重置错误码
	*/
				struct msgbuf {
	
	           		long mtype;       /* 消息的类型 必须大于 0 */
	
	           		char mtext[1];    /* 消息正文 可以自定义 */
	       		};
  • msgrcv函数:
  • 功能:在消息队列中读取一条消息;
	ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
	/*
		参数:
		
		    	msqid:消息队列的id
		
		    	msgp: 用来保存接收的数据的缓冲区的首地址
		
		    	msgsz:消息正文的大小
		
		    	msgtyp:要接受的消息的类型
		
		        		0 :接收消息队列中第一条消息
		
		        		>0 : 接收指定类型的第一条消息
		
		        		<0 :一般不使用,
		
						表示接收消息队列中第一条类型最小的小于msgtyp的绝对值的消息
		
		            		3-2-5-500-200-8
		
		            		读取时,类型传 -200
		
		            		读取的顺序  2-3-5 
		
		    	msgflg:标志位 0 阻塞接收  IPC_NOWAIT 非阻塞接收
		
		返回值:
		
		    	成功 实际读到的正文的字节数
		
		    	失败 -1  重置错误码
	 */
    	struct msgbuf {

           		long mtype;       /* 消息的类型 必须大于 0 */

           		char mtext[1];    /* 消息正文 可以自定义 */

       	};
  • msgctl函数:
  • 功能:控制消息队列;
	int msgctl(int msqid, int cmd, struct msqid_ds *buf);
	/*
		参数:
		
		    	msqid:消息队列id
		
		    	cmd:指令
		
		        		IPC_STAT:获取消息队列的属性
		
		        		IPC_SET:设置消息队列的属性
		
		        		IPC_RMID:立即删除消息队列
		
		            			只有消息队列的创建者和所有者以及root用户可以删除消息队列
		
		            			msgctl函数的第三个参数被忽略
		    	buff:
		返回值:
		
		    	成功 	0
		
		    	失败 	-1  	重置错误码
	 */
  • 示例代码(不关注类型):
  • 写端:
	#include 
	#include 
	#include 
	
	#include 
	#include 
	
	#include 
	#include 
	
	//不关注类型
	
	typedef struct msg
	{
	    long mtype; //消息的类型 必须大于 0
	    char buf[256];  //消息正文 可以自定义
	
	}msg_t;
	
	int main(int argc, char const *argv[])
	{
	    
	    //获取IPC通信的键值
	    key_t key = ftok("/home/linux/work/MSG", 'k');
	    if(-1 == key)
	    {
	        perror("ftok error");
	    }
	    //创建一个消息队列
	    int msqid = msgget(key, IPC_CREAT|0666);
	    if(-1 == msqid)
	    {
	        perror("msgget error");
	    }
	    printf("msqid = %d\n", msqid);
	
	    msg_t msg = {.mtype = 100};
	
	    while(1)
	    {
	        fgets(msg.buf,sizeof(msg.buf),stdin);
	        msg.buf[strlen(msg.buf)-1] = '\0';
	        if(!strncmp(msg.buf,"quit",4))
	        {
	            break;
	        }
	        //向消息队列中写入一条消息
	        msgsnd(msqid,&msg,sizeof(msg)-sizeof(msg.mtype),0);
	    }
	
	    //删除消息队列
	    if(-1 == msgctl(msqid,IPC_RMID,NULL))
	    {
	        perror("msgctl error");
	    }
	
	    return 0;
	}

  • 读端:
	#include 
	#include 
	#include 
	
	#include 
	#include 
	
	#include 
	#include 
	
	//不关注类型
	
	typedef struct msg
	{
	    long mtype;     //消息的类型 必须大于 0
	    char buf[256];  //消息正文 可以自定义
	
	}msg_t;
	
	int main(int argc, char const *argv[])
	{
	    //获取IPC通信的键值
	    key_t key = ftok("/home/linux/work/MSG", 'k');
	    if(-1 == key)
	    {
	        perror("ftok error");
	    }
	    //创建一个消息队列
	    int msqid = msgget(key, IPC_CREAT|0666);
	    if(-1 == msqid)
	    {
	        perror("msgget error");
	    }
	    printf("msqid = %d\n", msqid);
	
	    msg_t msg;
	    int type = 0;
	    while(1)
	    {
	        //忽略类型,每次都输入0
	        scanf("%d",&type);
	        msgrcv(msqid, &msg,sizeof(msg)-sizeof(msg.mtype), type, 0);
	        printf("%ld:[%s]\n",msg.mtype,msg.buf);
	
	    }
	
	    //删除消息队列
	    if(-1 == msgctl(msqid,IPC_RMID,NULL))
	    {
	        perror("msgctl error");
	    }
	    return 0;
	}

  • 运行结果:
	linux@ubuntu:~/work/MSG$ gcc w1.c -o w1
	linux@ubuntu:~/work/MSG$ ./w1
	msqid = 5
	hello
	china
	hi
	linux@ubuntu:~/work/MSG$ gcc r1.c -o r1
	linux@ubuntu:~/work/MSG$ ./r1
	msqid = 5
	0
	100:[hello]
	0
	100:[china]
	0
	100:[hi]
  • 示例代码(关注类型):
  • 写端:
	//关注类型
	
	#include 
	#include 
	#include 
	
	#include 
	#include 
	
	#include 
	#include 
	
	//消息结构体
	typedef struct MSG
	{
	    long mtype;
	    int id;
	    char name[32];
	    int score;
	
	}msg_t;
	
	int main(int argc, char const *argv[])
	{
	    //获取IPC通信的键值
	    key_t key = ftok("/home/linux/work/MSG", 'k');
	    if(-1 == key)
	    {
	        perror("ftok error");
	    }
	    //创建一个消息队列
	    int msqid = msgget(key, IPC_CREAT|0666);
	    if(-1 == msqid)
	    {
	        perror("msgget error");
	    }
	    printf("msqid = %d\n", msqid);
	
	    //发送消息
	    msg_t msg1 = {
	
	        .mtype = 120,
	        .id = 1001,
	        .name = "lk",
	        .score = 99,
	    };
	
	    msgsnd(msqid, &msg1, sizeof(msg1) - sizeof(long), 0);
	
	    msg_t msg2 = {
	
	        .mtype = 110,
	        .id = 1002,
	        .name = "smd",
	        .score = 98,
	    };
	
	    msgsnd(msqid, &msg2, sizeof(msg2) - sizeof(long), 0);
	
	    msg_t msg3 = {
	
	        .mtype = 130,
	        .id = 1003,
	        .name = "wjy",
	        .score = 94,
	    };
	
	    msgsnd(msqid, &msg3, sizeof(msg3) - sizeof(long), 0);
	
	     msg_t msg4 = {
	
	        .mtype = 111,
	        .id = 1004,
	        .name = "syj",
	        .score = 94,
	    };
	
	    msgsnd(msqid, &msg4, sizeof(msg4) - sizeof(long), 0);
	
	    return 0;
	}

  • 读端:
	#include 
	#include 
	#include 
	
	#include 
	#include 
	
	#include 
	#include 
	
	//消息结构体
	typedef struct MSG
	{
	    long mtype;
	    int id;
	    char name[32];
	    int score;
	
	}msg_t;
	
	int main(int argc, char const *argv[])
	{
	    //获取IPC通信的键值
	    key_t key = ftok("/home/linux/work/MSG", 'k');
	    if(-1 == key)
	    {
	        perror("ftok error");
	    }
	    //创建一个消息队列
	    int msqid = msgget(key, IPC_CREAT|0666);
	    if(-1 == msqid)
	    {
	        perror("msgget error");
	    }
	    printf("msqid = %d\n", msqid);
	
	    msg_t msg;
	    long type;
	    while(1)
	    {
	        memset(&msg, 0, sizeof(msg_t));
	        printf("请输入要接收消息的类型\n");
	        scanf("%ld", &type);
	        msgrcv(msqid, &msg, sizeof(msg) - sizeof(long), type, 0);
	        printf("[%ld][%d][%s][%d]\n",msg.mtype, msg.id, msg.name, msg.score);
	    }
	
	    //删除消息队列
	    if(-1 == msgctl(msqid, IPC_RMID,NULL))
	    {
	        perror("msgctl error");
	    }
	    return 0;
	}

  • 运行结果:
	linux@ubuntu:~/work/MSG$ gcc w2.c -o w2
	linux@ubuntu:~/work/MSG$ ./w2
	msqid = 7
	linux@ubuntu:~/work/MSG$ gcc r2.c -o r2
	linux@ubuntu:~/work/MSG$ ./r2
	msqid = 7
	请输入要接收消息的类型
	120
	[120][1001][lk][99]
	请输入要接收消息的类型
	111
	[111][1004][syj][94]
	请输入要接收消息的类型
	130
	[130][1003][wjy][94]
	请输入要接收消息的类型
	110
	[110][1002][smd][98]

你可能感兴趣的:(多进程间通信学习系列,学习,C语言,前端,算法,linux,运维)