[Linux]消息队列

我们知道进程间通信的方法有多种,主要有管道,消息队列,信号量,共享内存,socket等。之前介绍过管道,今天再介绍一个新的概念–消息队列

消息队列:将一个进程到另一个进程之间发送数据块的方式。这些发送的数据块需要存在一个消息队列缓冲区中。这些数据块都是有一定的类型的,我们可以通过存放消息的数据块来避免命名管道与匿名管道所带来的同步与阻塞问题。与管道不同的是,消息队列是基于消息的,而管道是基于字节流的。同时,消息队列中存放的消息的数量是有限的。有最大长度(MSGMAX)和消息队列的总的字节数(MSGMNB)。也有系统规定的消息队列的总数(MSGMNI)。

这里写图片描述

内核为每个IPC对象维护了一个数据结构:struct ipc;


struct ipc_perm {
key_t __key; /* ftok所获取的唯一标识的key值*/
uid_t uid; /* 拥有者的有效uid*/
gid_t gid; /* 拥有者的有效gid */
uid_t cuid; /* 创建者的有效uid*/
gid_t cgid; /* 创建者的有效gid */
unsigned short mode; /* 权限 */
unsigned short __seq; /* 序列号*/

注:

消息队列,信号量,共享内存都有一个ipc数据结构。

在/usr/include/linux/msg.h下,有一个消息队列的数据结构:

这里写图片描述

由图可以看到ipc_perm就是刚刚说的几种通信方式所共有的数据结构。其他的一些就是消息队列结构体所私有的特性。还有其中的msg_first指针和msg_last指针分别指向消息队列的第一条消息和最后的消息。消息队列是用链表实现的。

这里写图片描述

同样,这幅图也是在msg.h中的。这里是消息缓冲区结构体和对于消息的一些信息。msgbuf结构体中的mtype是写的消息的长度大小,即mtext的size。数组mtext即是存放消息的数组。

消息队列的具体实现:

1.创建消息队列:

int msgget(key_t key,int msgflag);

key可以认为是端口号,由ftok生成一个唯一的key值。用来创建消息队列。

msgflag:是创建的消息队列的方式,有IPC_CREAT和IPC_EXCL。

(1)IPC_CREAT:单独使用时,如果已经存在已有的IPC资源,就直接返回已存在的IPC,如果不存在则创建一个新的IPC资源。

(2)IPC_CREAT|IPC_EXCL:同时使用时表示,不存在则创建一个,存在的话返回错误消息。

2.将消息发送到消息队列中

int msgsnd(int msgid,const void* msgp,size_t msgsz,int msgflg);

msgid:表示唯一确定的一个消息队列的id。

msgp: 表示存放数据的消息缓冲区

msgsz:消息文本的大小

msgflg:表示在队列没有数据的情况下进行的操作。一般设置为0,表示当队列空或满的时候,以阻塞式等待的方式进行处理。

3.从消息队列中取消息

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

和上述往消息队列中写数据类似,这里取消息时,有msgtyp表示取哪种类型的消息,即消息队列中读取的消息形态。

4.设置消息队列的属性

int msgctl(int msgid,int cmd,struct msqid_ds *buf);

这里主要是对destroy进行操作,将cmd设置为IPC_RMID即可。

代码实现(server端与client端的通信):

//comm.h
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>#define PATHNAME "."
#define PROJ_ID 0x6666
#define SERVER_TYPE 1
#define CLIENT_TYPE 2struct msgbuf {long mtype;char mtext[1024];
};int createMsgqueue();
int getMsg();
int destroyMsg(int msgid);
int recvMsg(int msgid,long recvtype,char out[]);
int sendMsg(int msgid,long who,char* msg);#endif   //_COMM_H//comm.c
#include"comm.h"int commMsgqueue(int flags)
{key_t _key = ftok(PATHNAME,PROJ_ID);if(_key < 0){perror("ftok");return -1;}int msgid = msgget(_key,flags);if(msgid < 0){perror("msgget");return -2;}return msgid;
}int createMsgqueue()
{return commMsgqueue(IPC_CREAT | IPC_EXCL|0666);
}
int getMsg()
{return commMsgqueue(IPC_CREAT);
}
int destroyMsg(int msgid)
{if(msgctl(msgid,IPC_RMID,NULL) < 0){perror("msgctl");return -1;}return 0;
}int recvMsg(int msgid,long recvtype,char out[])
{struct msgbuf buf;if(msgrcv(msgid,(void*)&buf,sizeof(buf.mtext),recvtype,0) < 0){perror("msgrcv");return -1;}strcpy(out,buf.mtext);return 0;
}int sendMsg(int msgid,long who,char* msg)
{struct msgbuf buf;buf.mtype=who;strcpy(buf.mtext,msg);if(msgsnd(msgid,(void*)&buf,sizeof(buf.mtext),0) < 0){perror("msgsnd");return -1;}return 0;
}//server.c
#include"comm.h"
#include<stdio.h>int main()
{int msgid = createMsgqueue();char buf[1024];while(1){buf[0]=0;recvMsg(msgid,CLIENT_TYPE,buf);printf("client# %s\n",buf);printf("please Enter# ");fflush(stdout);ssize_t s = read(0,buf,sizeof(buf));if(s > 0){buf[s-1] = 0;sendMsg(msgid,SERVER_TYPE,buf);printf("send done,wait recv...\n");}}destroyMsg(msgid);return 0;
}//client.c
#include"comm.h"
#include<stdio.h>int main()
{int msgid = createMsgqueue();char buf[1024];while(1){buf[0]=0;recvMsg(msgid,CLIENT_TYPE,buf);printf("client# %s\n",buf);printf("please Enter# ");fflush(stdout);ssize_t s = read(0,buf,sizeof(buf));if(s > 0){buf[s-1] = 0;sendMsg(msgid,SERVER_TYPE,buf);printf("send done,wait recv...\n");}}destroyMsg(msgid);return 0;
}
[xiaoxu@bogon msgqueue]$ cat client.c 
#include<stdio.h>
#include"comm.h"int main()
{int msgid = getMsg();char buf[1024];while(1){buf[0]=0;printf("please Enter# ");fflush(stdout);ssize_t s = read(0,buf,sizeof(buf));if(s > 0){buf[s-1] = 0;sendMsg(msgid,CLIENT_TYPE,buf);printf("send done,wait recv...\n");}recvMsg(msgid,SERVER_TYPE,buf);printf("server# %s\n",buf); 
}return 0;
}
//Makefile
.PHONY:all
all:client serverclient:client.c comm.cgcc -o $@ $^
server:server.c comm.cgcc -o $@ $^.PHONY:clean
clean:rm -f server client

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/382720.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++关键字速查手册

[TOC] https://blog.csdn.net/csdn_kou/article/details/81113215 C98关键字 C11 关键字共73个 alignas alignof用于获取取指定表达式指定的&#xff08;类似sizeof&#xff0c;可以直接是类型名&#xff09;的对齐(alignment)。alignas用于声明时指定对齐类似于现有的类型…

[Linux]信号

Linux下的信号是一个什么概念呢。我们在现实生活中也遇到过信号之类的。比如红绿信号灯&#xff0c;班主任叫你去办公室并且脸色不好&#xff0c;诸如此类的都会给你一个信号。让你辨别事情的发生。同样&#xff0c;Linux下也有许多的信号&#xff0c;让你执行相应的操作。比如…

[数据结构]Map和Set

说起map和set&#xff0c;想必我们都学过红黑树了吧&#xff0c;map和set就是红黑树的一个应用领域。它的底层就是由红黑树来实现的。下面简单说一下map和set的使用吧。 首先&#xff0c;有一个栗子是这样的&#xff0c;让我们统计出每种水果出现的次数。 我们会想到怎么解决…

linux之信号

信号&#xff1a;在生活中&#xff0c;我们遇到过不同种类的信号&#xff0c;比如&#xff1a;&#xff08;交通信号&#xff0c;乃至某个人的表情&#xff0c;动作等带给你不同的信号&#xff09;然而&#xff0c;在我们的linux下&#xff0c;我们最熟悉的就是&#xff0c;当遇…

[Linux]继续探究mysleep函数(竞态条件)

之前我们探究过mysleep的简单用法&#xff0c;我们实现的代码是这样的&#xff1a; #include<stdio.h> #include<signal.h>void myhandler(int sig) {}unsigned int mysleep(unsigned int timeout) {struct sigaction act,oact;act.sa_handler myhandler;sigempt…

[Linux]死锁

死锁是指多个进程在运行过程中因争夺资源而造成的一种僵局&#xff0c;当进程处于这种僵持状态时&#xff0c;若无外力作用&#xff0c;它们都将无法再向前推进。之前信号量的时候我们知道&#xff0c;如果多个进程等待&#xff0c;主要体现在占有锁的问题上。死锁也可以被定义…

[Linux]线程安全和可重入函数

线程安全&#xff1a;一个函数被称为线程安全的&#xff0c;当且仅当被多个并发进程反复调用时&#xff0c;它会一直产生正确的结果。如果一个函数不是线程安全的&#xff0c;我们就说它是线程不安全的。 重入&#xff1a;函数被不同的控制流程调用,有可能在第一次调用还没返回…

[Linux]信号量

信号量是一个计数器&#xff0c;用于为多个进程提供对共享数据对象的访问。 在信号量上只有三种操作可以进行&#xff0c;初始化、递增和增加&#xff0c;这三种操作都是原子操作。递减操作可以用于阻塞一个进程&#xff0c;增加操作用于解除阻塞一个进程。 为了获得共享资源…

[Linux]关于SIGCHLD

之前我们就学过&#xff0c;关于wait和waitpid来处理僵尸进程&#xff0c;父进程等待子进程结束后自己才退出&#xff0c;这样的方法有俩种方式&#xff0c;一种是父进程死死的等子进程退出&#xff0c;也就是使用阻塞的方式等待子进程退出&#xff0c;另一种方式是通过非阻塞的…

C语言思维导图

本人能力有限&#xff0c;知识点难免概括不全&#xff0c;如有错误欢迎指正

pthread和互斥量条件变量函数意义速查表

数据类型 pthread_t 线程 互斥量和条件变量

[Linux]共享内存

共享内存是UNIX提供的进程间通信手段中速度最快的一种&#xff0c;也是最快的IPC形式。为什么是最快的呢&#xff0c;因为数据不需要在客户进程和服务器进程之间复制&#xff0c;所以是最快的一种IPC。这是虚存中由多个进程共享的一个公共内存块。 两个不同进程A、B共享内存的…

[Linux]gdb调试多进程多线程例程

gdb相信学linux的同学已经比较熟悉了吧&#xff0c;它是linux下代码调试工具。我们在写c语言&#xff0c;c的代码时经常会用到&#xff0c;它有一些常用的调试命令: run&#xff08;r&#xff09;&#xff1a;运行程序&#xff0c;如果有断点在下一个断点处停止 start&#xf…

[Linux]守护进程(精灵进程)

一、守护进程是什么 守护进程是生存期很长的一种进程&#xff0c;可以说它是7*24小时工作的。&#xff08;什么是7*24&#xff0c;一周7天&#xff0c;每天24小时&#xff0c;这不就是一年365天一直在工作嘛&#xff0c;还搞的这么诙谐&#xff0c;哈哈&#xff09;。它们常常…

浅谈shell中的clear命令实现

NAME(名称) clear - 清除终端屏幕 SYNOPSIS(总览) clear DESCRIPTION(描述) clear可以在允许的情况下清屏. 它会在环境变量中查找终端的类型, 然后到terminfo数据库中找出清屏的方法. 《man手册》 #include <stdio.h>int clear_main(int argc, char **argv) {/* Th…

[Linux]ARP协议

概念&#xff1a; 1. ARP协议(地址解析协议):由IP地址转换为MAC地址的协议。IP地址&#xff1a;网络号主机号。MAC地址&#xff1a;数据链路层的物理地址&#xff08;硬件地址&#xff09;。IP协议使用了ARP协议&#xff0c;因此被划归为网络层&#xff0c;但其用途是从网络层…

Makefile使用及多文件gdb 调试

文件内容 [koulocalhost makefile]$ cat 1.c #include "3.h" int main() {key_t key ftok(".",1);printf("%d\n",add(1,2));return 0; }[koulocalhost makefile]$ cat 2.c #include "3.h" int add(int a, int b) {return a b; } [k…

[Linux]CRC校验

CRC(Cyclic Redundancy Check),循环冗余校验码&#xff0c;是数据通信领域中最常用的一种差错校验码&#xff0c;其特征是信息字段和校验字段的长度可以任意选定。 CRC校验步骤&#xff1a; CRC分为两部分&#xff0c;前部分为信息码&#xff0c;后部分为校验码&#xff1b;设…

python字符串系列

1.find方法用于在长串中查找子串&#xff0c;返回子串中最左位置的下标&#xff0c;如果没找到&#xff0c;则返回-1 2.join方法用于在队列中添加元素 3.lower返回字符串的小写字母版 4.replace返回字符串中所有匹配项均被替换之后得到字符串 5.split将字符串分割成序列 6.stri…

linux网络编程Internet Socket地址,套接字,和函数

文章内容节选《linux/UNIX 系统网络编程》 Internet domain socket地址有两种&#xff1a;IPv4 IPv6 IPv4被存储在结构体中&#xff0c; 该结构体在 netinet/in.h 中进行定义 cd usr/include/netinet/in.h struct in_addr {in_addr_t s_addr; //32位IPv4地址 }struct so…