进程学习:进程间通信(system v IPC)1.消息队列
来源:互联网 发布:中国电信网络传真 编辑:程序博客网 时间:2024/06/05 14:10
消息队列与管道的异同点:
消息队列与管道的相同点:
1.都是利用内核的1G空间来通信(如图);
消息队列与管道的不同点:
1.管道的数据读取是严格按照先进先出;
2.消息队列的数据读取可以按照数据类型进行读取;
消息队列函数
一、int msgget(key_t key, int msgflg);
1.功能:创建或打开一个消息队列
2.参数:
key:两种方式:1-由ftok函数获得;2-直接填写IPC_PRIVATE(此时系统会分配一个唯一的key值)
msgflg:打开的方式
IPC_CREAT:没有消息队列的话,创建一个新的消息队列,如果已有有相同msgid的消息队列,则返回已有消息队列的msgid;
IPC_EXCL:不可单独使用。与IPC_CREAT结合使用时(IPC_CREAT|IPC_EXCL),如果已有相同msgid的消息队列存在,则返回一个EEXIST错误,因为已存在;
读写权限:与文件权限一样。(IPC_CREAT | IPC_EXCL | 0664)
3.返回值:
成功:返回相应的msgid值;
错误:返回-1;
二、int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg);
1.功能:向值为msgid的消息队列发送一个消息
2.参数:
msgid:目标消息队列的msgid值
msgq:要发送消息的结构体地址
msgsz:要发送的消息大小,结构体总大小减去消息类型大小 sizeof(struct msgbuf) - sizeof(long)
msgflg:以阻塞(0)或者非阻塞(IPC_NOWAIT)的模式发送
3.返回值:
成功:返回 0
失败:返回 -1
要发送消息的结构体模板struct msgbuf{ long msgtype; //大于0 消息正文,可以自定义类型}
三、int msgrcv(int msgid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
1.功能:从消息队列读取一条消息
2.参数:
msgid:同msgsnd();
msgp:要存放接收到消息的结构体地址
msgsz:要接收正文的长度sizeof(struct msgbuf) - sizeof(long)
msgtyp:接收消息的类型,区别于管道的这个关键点。
msgtyp = 0:按先进先出逐个读取数据,与管道无异;
msgtyp > 0:表示要接收类型为msgtyp的消息;
msgtyp < 0:表示要接收类型为 [ 小于(msgtyp的绝对值中)] 最小的类型的消息
3.返回值:
成功:返回 0
失败:返回 -1
四、int msgctl(int msqid, int cmd, struct msqid_ds *buf);
1.功能:控制消息队列
2.参数:
msqid:消息队列msgid号;
cmd:控制命令 IPC_STAT / IPC_SET / IPC_RMID
IPC_STAT:获取消息队列的属性,并放在第三个参数(struct msqid_ds *buf)内;
IPC_SET:设置消息队列的属性,要设置的属性放在第三个参数;
IPC_RMID:删除消息队列,此时第三个参数为NULL;
3.返回值:
成功:返回 0
失败:返回 -1
代码实例
下面咱们来写几个具体代码验证一下消息队列的特点;
第一个代码:从一个 terminal 输入,从另一个 terminal 读取并打印:(半双工通信方式)
/*在终端输入消息*/#include "msg.h"int main(int argc, const char *argv[]){key_t key;struct msgbuf sendbuf; //声明要发送的消息变量size_t sndsz = sizeof(sendbuf) - sizeof(long); //计算要发送的消息的大小,用作发送函数msgsnd的第3个参数int msgid; //生成key值if( (key = ftok(".", 1)) < 0){perror("ftok error");exit(1);}printf("key = %#0x\n", key); //打印key值,用十六进制打印if( (msgid = msgget(key, IPC_CREAT|IPC_EXCL|0664)) < 0){if(errno == EEXIST) //如果错误值是EEXIST,意思就是这个消息队列已经存在的话,就执行下面的代码{msgid = msgget(key, 0664); //不创建,只打开消息id为msgid的消息队列printf("messageid %d -- key %#0x is exist\n", msgid, key);}else {perror("msgget error");exit(1);}}else{printf("msgid: %d -- key: %#0x\n is created\n", msgid, key);}system("ipcs -q");sendbuf.msgtype = 1; //给这个sendbuf变量定义一个类型,用于接收方选择性接收while(fgets(sendbuf.buf, N, stdin) != NULL){msgsnd(msgid, &sendbuf, sndsz, 0);system("ipcs -q");if(strncmp(sendbuf.buf, "quit", 4) == 0){break;}}return 0;}
/*从终端读取并打印消息*/#include "msg.h"int main(int argc, const char *argv[]){key_t key;int msgid;struct msgbuf rcvbuf;size_t rcvsz = sizeof(rcvbuf) - sizeof(long);ssize_t rcvnum;char sysbuf[N];if( (key = ftok(".", 1)) < 0){perror("ftok error");exit(1);}printf("key = %#0x\n", key);if( (msgid = msgget(key, IPC_CREAT|IPC_EXCL|0664)) < 0){if(errno == EEXIST){msgid = msgget(key, 0664);printf("messageid %d -- key %#0x is exist\n", msgid, key);}else{perror("msgget error");exit(1);}}else{printf("msgid: %d -- key: %#0x\n is created\n", msgid, key);}rcvbuf.msgtype = 1; //注意msgrcv的第4个参数是要接收的消息的类型,如果是0的话,就是按先进先出的方式接收,此时和管道一样;while( (rcvnum = msgrcv(msgid, &rcvbuf, rcvsz, 0, 0)) > 0){if(strncmp(rcvbuf.buf, "quit", 4) == 0){break;sprintf(sysbuf, "ipcrm -q %d", msgid);system(sysbuf);system("ipcs -q");}system("ipcs -q");fputs(rcvbuf.buf, stdout);}return 0;}
Makefile:利用了 Makefile 的隐晦规则以及伪目标;
.PHONY:allcleanall:write readwrite:read:clean:-rm write read
第二个代码:建立两个 terminal ,并且每个 terminal 均可以向对方发生消息,同时接收对方发送过来的消息(全双工通信模式)
注意发送和接收方的消息类型,这里容易出错的。
#include "msg.h"int main(int argc, const char *argv[]){key_t key;int msgid, pid;struct msgbuf sendbuf;size_t sndsz = sizeof(sendbuf) - sizeof(long);struct msgbuf recvbuf;size_t rcvsz = sizeof(recvbuf) - sizeof(long);if( (key = ftok(".", 1)) < 0){perror("ftok error");exit(1);}if( (msgid = msgget(key, IPC_CREAT|IPC_EXCL|0664)) < 0){if(errno == EEXIST){msgid = msgget(key, 0664);printf("key:%#0x msgid:%d --message queue is exist\n", key, msgid);}else{perror("msgget error");kill(getpid(), SIGKILL);}}if( (pid = fork()) < 0){perror("fork error");exit(1);}else if(pid == 0){sendbuf.msgtype = 2;while(fgets(sendbuf.buf, N, stdin) != NULL){msgsnd(msgid, &sendbuf, sndsz, 0);if(strncmp(sendbuf.buf, "quit", 4) == 0){kill(pid, SIGKILL);exit(5);}}raise(SIGKILL);}else if(pid > 0){int status, out_pid;recvbuf.msgtype = 2;while(msgrcv(msgid, &recvbuf, rcvsz, 1, 0) > 0){if(strncmp(recvbuf.buf, "quit", 4) == 0){exit(5);}fputs(recvbuf.buf, stdout);}while(1){out_pid = waitpid(-1, &status, WNOHANG);}if(WIFEXITED(status)){printf("over_process, pid = %d, exitnum = %d\n", out_pid,WEXITSTATUS(status));}}return 0;}
#include "msg.h"int main(int argc, const char *argv[]){key_t key;int msgid, pid;struct msgbuf sendbuf;size_t sndsz = sizeof(sendbuf) - sizeof(long);struct msgbuf recvbuf;size_t rcvsz = sizeof(recvbuf) - sizeof(long);if( (key = ftok(".", 1)) < 0){perror("ftok error");exit(1);}if( (msgid = msgget(key, IPC_CREAT|IPC_EXCL|0664)) < 0){if(errno == EEXIST){msgid = msgget(key, 0664);printf("key:%#0x msgid:%d --message queue is exist\n", key, msgid);}else{perror("msgget error");kill(getpid(), SIGKILL);}}if( (pid = fork()) < 0){perror("fork error");exit(1);}else if(pid == 0){sendbuf.msgtype = 1;while(fgets(sendbuf.buf, N, stdin) != NULL){msgsnd(msgid, &sendbuf, sndsz, 0);if(strncmp(sendbuf.buf, "quit", 4) == 0){kill(pid, SIGKILL);exit(5);}}raise(SIGKILL);}else if(pid > 0){int status, out_pid;recvbuf.msgtype = 1;while(msgrcv(msgid, &recvbuf, rcvsz, 2, 0) > 0){if(strncmp(recvbuf.buf, "quit", 4) == 0){exit(5);}fputs(recvbuf.buf, stdout);}while(1){out_pid = waitpid(-1, &status, WNOHANG);}if(WIFEXITED(status)){printf("over_process, pid = %d, exitnum = %d\n", out_pid,WEXITSTATUS(status));}}return 0;}
- 进程学习:进程间通信(system v IPC)1.消息队列
- Linux C编程--进程间通信(IPC)5--System V IPC 机制1--消息队列
- Linux C编程--进程间通信(IPC)5--System V IPC 机制1--消息队列
- System V 进程间通信(IPC)之System V 消息队列
- Linux进程间通信(IPC)编程实践(三) 详解System V消息队列(1)
- linux—进程通信IPC--system v-消息队列
- System V进程间通信---消息队列
- UNPv2:进程间通信(三) System V 消息队列
- 【十】 进程间通信——[System V IPC对象]消息队列(message queue)
- Linux进程间通信(IPC)编程实践(四) 详解System V消息队列(2)(msgsnd & msgrcv)
- 进程通信学习笔记(System V消息队列)
- Linux 进程通信(System V)消息队列
- 进程间通信(7) - 消息队列(System V)
- linux进程间通信-----System V消息队列总结实例
- System V进程间通信—— 消息队列
- 进程学习:进程间通信(system v IPC)2.共享内存
- 进程学习:进程间通信(system v IPC)3.信号灯
- linux基础编程:进程通信之System V IPC:消息队列,信号量,共享内存
- git 命令大全
- 浪漫的漫天爱心01(java)
- javascript介绍及如何在html中使用js与jQuery
- 中国程序员如何升职加薪,也许我们该学学印度人
- android7.0打电话是否是紧急号码
- 进程学习:进程间通信(system v IPC)1.消息队列
- 第7章 航空公司客户价值分析
- 浪漫的漫天爱心02(java)
- 1190: 確率
- wex5的跨域AJAX请求
- 将生成jsp放到非webapps 目录下
- Android踩坑日记:点击变暗效果的ImageView实现原理
- 利用可变列数组实现乘法口诀打印。
- hibernate持久化对象的状态