1,消息队列
2,消息队列结构
3,消息队列使用步骤
3.1,打开/创建消息队列 msgget()
#include
#include
int msgget(key_t key, int msgflg);
3.1.1,打开/创建消息队列—示例msgget()
……
int main()
{
int msgid;
key_t key;
if ((key = ftok(“.”, ‘q’)) == -1) {
perror(“ftok”); exit(-1);
}
if ((msgid = msgget(key, IPC_CREAT|0666)) < 0) {
perror(“msgget”); exit(-1);
}
……
return 0;
}
3.2,向消息队列发送消息 msgsnd()
#include
#include
int msgsnd(int msgid, const void *msgp, size_t size,int msgflg);
3.2.1,消息格式
3.2.2,消息发送—示例
typedef struct
{
long mtype;
char mtext[64];
} MSG;
#define LEN (sizeof(MSG) – sizeof(long))
int main()
{
MSG buf;
……
buf.mtype = 100;
fgets(buf.mtext, 64, stdin);
msgsnd(msgid, &buf,LEN, 0);
……
return 0;
}
3.3,从消息队列接收消息 msgrcv()
#include
#include
int msgrcv(int msgid, void *msgp, size_t size, long msgtype,int msgflg);
3.3.1,消息接收—示例
typedef struct {
long mtype;
char mtext[64];
} MSG;
#define LEN (sizeof(MSG) – sizeof(long))
int main() {
MSG buf;
……
if (msgrcv(msgid, &buf,LEN, 200, 0) < 0) {
perror(“msgrcv”);
exit(-1);
}
……
}
3.4,控制消息队列 msgctl()
#include
#include
int msgctl(int msgid, int cmd, struct msqid_ds *buf);
消息队列的删除和共享内存不一样。共享内存系统会检查,所有进程都取消映射了才会真的删除,而消息只要进程一执行IPC_RMID,消息队列会立刻被删除
4,消息队列—示例
要求:两个进程通过消息队列轮流将键盘输入的字符串发送给对方,接收并打印对方发送的消息
/******clientA.c******/
#include
#include
#include
#include
#include
#include
#include
typedef struct{
long mtype;
char mtext[64];
}MSG;
#define LEN (sizeof(MSG) - sizeof(long))
#define TypeA 100
#define TypeB 200
int main(int argc, const char *argv[])
{
key_t key;
int msgid;
MSG buf;
if((key = ftok(".",'q')) < 0)
{
perror("ftok");
exit(-1);
}
if((msgid = msgget(key,IPC_CREAT|0666)) < 0)
{
perror("msgget");
exit(-1);
}
while(1)
{
buf.mtype = TypeB;
printf("input >");
fgets(buf.mtext,64,stdin);
msgsnd(msgid,&buf,LEN,0);
if(msgrcv(msgid,&buf,LEN,TypeA,0) < 0)
{
perror("msgrcv");
exit(-1);
}
printf("recv from clientB: %s",buf.mtext);
}
return 0;
}
/******clientB.c******/
#include
#include
#include
#include
#include
#include
#include
typedef struct{
long mtype;
char mtext[64];
}MSG;
#define LEN (sizeof(MSG) - sizeof(long))
#define TypeA 100
#define TypeB 200
int main(int argc, const char *argv[])
{
key_t key;
int msgid;
MSG buf;
if((key = ftok(".",'q')) < 0)
{
perror("ftok");
exit(-1);
}
if((msgid = msgget(key,IPC_CREAT|0666)) < 0)
{
perror("msgget");
exit(-1);
}
while(1)
{
if(msgrcv(msgid,&buf,LEN,TypeB,0) < 0)
{
perror("msgrcv");
exit(-1);
}
printf("recv from clientA: %s",buf.mtext);
buf.mtype = TypeA;
printf("input >");
fgets(buf.mtext,64,stdin);
msgsnd(msgid,&buf,LEN,0);
}
return 0;
}
步骤 | 终端一 | 终端二 |
---|---|---|
·在终端一运行clinntA ·在终端二中可用命令ipcs -q看到系统消息队列中多了一消息队列 |
linux@linux:~/test/interprocess/message_queue$ ./clientA.out |
linux@linux:~/test/interprocess/message_queue$ ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages 0x7107f38d 32768 linux 666 0 0 |
·在终端二运行clinntB ·在两个中断中可以交替输入,打印信息 |
linux@linux:~/test/interprocess/message_queue$ ./clientA.out input >ABC input >recv from clientB: ZXCV |
linux@linux:~/test/interprocess/message_queue$ ./clientB.out recv from clientA: ABC input >ZXCV |
·在终端二关闭clinntB(Ctrl-C) ·在终端一中继续输入 ·在终端二中可用命令ipcs -q看到系统消息队列仍然存在 |
input >qwe |
^C linux@linux:~/test/interprocess/message_queue$ ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages 0x7107f38d 32768 linux 666 64 1 |
·在终端二输入ipcrm -q 32768手动删除消息队列 ·可以在终端一中看到clinntA自动结束运行 |
linux@linux:~/test/interprocess/message_queue$ ipcrm -q 32768 |
改进,增添退出处理,程序结束,自动删除消息队列
/******clientA.c******/
#include
#include
#include
#include
#include
#include
#include
typedef struct{
long mtype;
char mtext[64];
}MSG;
#define LEN (sizeof(MSG) - sizeof(long))
#define TypeA 100
#define TypeB 200
int main(int argc, const char *argv[])
{
key_t key;
int msgid;
MSG buf;
if((key = ftok(".",'q')) < 0)
{
perror("ftok");
exit(-1);
}
if((msgid = msgget(key,IPC_CREAT|0666)) < 0)
{
perror("msgget");
exit(-1);
}
while(1)
{
buf.mtype = TypeB;
printf("input >");
fgets(buf.mtext,64,stdin);
msgsnd(msgid,&buf,LEN,0);
if(strcmp(buf.mtext,"quite\n") == 0)break;
if(msgrcv(msgid,&buf,LEN,TypeA,0) < 0)
{
perror("msgrcv");
exit(-1);
}
if(strcmp(buf.mtext,"quite\n") == 0)
{
msgctl(msgid,IPC_RMID,NULL);
exit(0);
}
printf("recv from clientB: %s",buf.mtext);
}
return 0;
}
/******clientB.c******/
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct{
long mtype;
char mtext[64];
}MSG;
#define LEN (sizeof(MSG) - sizeof(long))
#define TypeA 100
#define TypeB 200
int main(int argc, const char *argv[])
{
key_t key;
int msgid;
MSG buf;
if((key = ftok(".",'q')) < 0)
{
perror("ftok");
exit(-1);
}
if((msgid = msgget(key,IPC_CREAT|0666)) < 0)
{
perror("msgget");
exit(-1);
}
while(1)
{
if(msgrcv(msgid,&buf,LEN,TypeB,0) < 0)
{
perror("msgrcv");
exit(-1);
}
if(strcmp(buf.mtext,"quite\n") == 0)
{
msgctl(msgid,IPC_RMID,NULL);
exit(0);
}
printf("recv from clientA: %s",buf.mtext);
buf.mtype = TypeA;
printf("input >");
fgets(buf.mtext,64,stdin);
msgsnd(msgid,&buf,LEN,0);
if(strcmp(buf.mtext,"quite\n") == 0)break;
}
return 0;
}
改进思路:
·通过多进程/线程实现同时收发消息
·引入服务器端,实现不同通信方式
/******clientA.c******/
#include
#include
#include
#include
#include
#include
#include
typedef struct{
long mtype;
char mtext[64];
}MSG;
#define LEN (sizeof(MSG) - sizeof(long))
#define TypeA 100
#define TypeB 200
int main(int argc, const char *argv[])
{
key_t key;
int msgid;
MSG buf;
pid_t pid;
if((key = ftok(".",'q')) < 0)
{
perror("ftok");
exit(-1);
}
if((msgid = msgget(key,IPC_CREAT|0666)) < 0)
{
perror("msgget");
exit(-1);
}
if((pid = fork()) < 0)
{
perror("fork");
exit(-1);
}
else if (pid == 0)
{
while(1)
{
buf.mtype = TypeB;
printf("input >");
fgets(buf.mtext,64,stdin);
msgsnd(msgid,&buf,LEN,0);
if(strcmp(buf.mtext,"quite\n") == 0)break;
}
}
else
{
while(1)
{
if(msgrcv(msgid,&buf,LEN,TypeA,0) < 0)
{
perror("msgrcv");
exit(-1);
}
if(strcmp(buf.mtext,"quite\n") == 0)
{
msgctl(msgid,IPC_RMID,NULL);
exit(0);
}
printf("recv from clientB: %s",buf.mtext);
}
kill(pid,SIGUSR1);
}
return 0;
}
/******clientB.c******/
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct{
long mtype;
char mtext[64];
}MSG;
#define LEN (sizeof(MSG) - sizeof(long))
#define TypeA 100
#define TypeB 200
int main(int argc, const char *argv[])
{
key_t key;
int msgid;
MSG buf;
pid_t pid;
if((key = ftok(".",'q')) < 0)
{
perror("ftok");
exit(-1);
}
if((msgid = msgget(key,IPC_CREAT|0666)) < 0)
{
perror("msgget");
exit(-1);
}
if((pid = fork()) < 0)
{
perror("fork");
exit(-1);
}
else if(pid == 0)
{
while(1)
{
if(msgrcv(msgid,&buf,LEN,TypeB,0) < 0)
{
perror("msgrcv");
exit(-1);
}
if(strcmp(buf.mtext,"quite\n") == 0)
{
msgctl(msgid,IPC_RMID,NULL);
exit(0);
}
printf("recv from clientA: %s",buf.mtext);
}
}
else
{
while(1)
{
buf.mtype = TypeA;
printf("input >");
fgets(buf.mtext,64,stdin);
msgsnd(msgid,&buf,LEN,0);
if(strcmp(buf.mtext,"quite\n") == 0)break;
}
kill(pid,SIGUSR1);
}
return 0;
}