一:消息队列
消息队列是进程间通信的一种手段,进程产生的数据块以链表的形式存储在消息队列中,每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型。
消息队列有以下的几个限制,每个消息有最大长度不能超过MSGMAX,每个消息队列的总的字节数不能超过MSGMNB,消息队列的总数不能超过MSGMNI。
root@epc:~# cat /proc/sys/kernel/msgmax
8192
root@epc:~# cat /proc/sys/kernel/msgmnb
16384
root@epc:~# cat /proc/sys/kernel/msgmni
32000
root@epc:~#
二:消息队列的数据结构
常用的IPC相关linux命令:
查看ipc:ipcs
删除:ipcrm -Q //只能删除非私有ipc,私有的ipc的key为0x0
ipcrm -q
struct ipc_perm {
key_t __key;
uid_t uid;
gid_t gid;
uid_t cuid;
gid_t cgid;
unsigned short mode;
unsigned short __seq;
};
root@epc:~# ipcs
------ Message Queues -------- =>消息队列
key msqid owner perms used-bytes messages
------ Shared Memory Segments -------- =>共享内存
key shmid owner perms bytes nattch status
------ Semaphore Arrays -------- =>信号量
key semid owner perms nsems
struct msqid_ds {
struct ipc_perm msg_perm;
time_t msg_stime;
time_t msg_rtime;
time_t msg_ctime;
unsigned long __msg_cbytes;
msgqnum_t msg_qnum;
msglen_t msg_qbytes;
pid_t msg_lspid;
pid_t msg_lrpid;
};
三:消息队列的函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgfl_g);
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
int msgsnd(int msqid, const void *msgp,size_t msgsz, int msgfl_g);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgfl_g)
四:利用System V消息队列实现简单的回射客户端/服务器
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<stdlib.h>
#include<string.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
}while(0)
#define MSGMAX 8192
struct Msgbuf{
long mtype;
char mtext[MSGMAX];
};
void echo_ser(int msgid)
{
struct Msgbuf msg;
memset(&msg, 0, sizeof(msg));
int nrcv = 0;
while (1)
{
if ((nrcv = msgrcv(msgid, &msg, MSGMAX, 1, 0)) < 0)
ERR_EXIT("msgrcv");
int pid = *((int *)msg.mtext);
printf("recv from pid=%d, length=%d, buf=%s\n", pid, nrcv, msg.mtext+4);
msg.mtype = pid;
msgsnd(msgid, &msg, nrcv, 0);
memset(&msg, 0, sizeof(msg));
}
}
int main(int argc, char *argv[])
{
int msgid;
msgid = msgget(1234, IPC_CREAT | 0666);
if (msgid == -1)
ERR_EXIT("msgget");
echo_ser(msgid);
return 0;
}
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#define ERR_EXIT(m) \
do { \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
#define MSGMAX 8192
struct Msgbuf
{
long mtype;
char mtext[MSGMAX];
};
void echo_cli(int msgid)
{
int nrcv;
int pid = getpid();
struct Msgbuf msg;
memset(&msg, 0, sizeof(msg));
while (fgets(msg.mtext+4, MSGMAX, stdin) != NULL)
{
msg.mtype = 1;
*((int *)msg.mtext) = pid;
if (msgsnd(msgid, &msg, 4 + strlen(msg.mtext + 4), IPC_NOWAIT) < 0)
ERR_EXIT("msgsnd");
if ((nrcv = msgrcv(msgid, &msg, MSGMAX, pid, 0)) < 0)
ERR_EXIT("msgsnd");
fputs(msg.mtext + 4, stdout);
memset(&msg, 0, sizeof(msg));
}
}
int main(int argc, char *argv[])
{
int msgid;
msgid = msgget(1234, 0);
if (msgid == -1)
ERR_EXIT("msgget");
echo_cli(msgid);
return 0;
}
五:实现每个客户一个队列
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>
#include<wait.h>
#include<unistd.h>
#include<errno.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
}while(0)
#define MSGMAX 8192
#define MSGQ_KEY 1234
#define MTYPE_GLOBAL 1
struct Msgbuf{
long mtype;
char mtext[MSGMAX];
};
void Handler(int signo)
{
pid_t pid;
int stat;
while ((pid = waitpid(-1, &stat, WNOHANG)) > 0);
return;
}
void echo_ser(int msgid)
{
signal(SIGCHLD, Handler);
struct Msgbuf msg;
memset(&msg, 0, sizeof(msg));
int nrcv = 0;
while (1)
{
do
{
nrcv = msgrcv(msgid, &msg, MSGMAX, MTYPE_GLOBAL, 0);
}while(nrcv<0 && errno==EINTR);
if (nrcv < 0)
ERR_EXIT("msgrcv");
int clientMsgid = *((int *)msg.mtext);
printf("recv from clientMsgid=%d, length=%d, buf=%s", clientMsgid, nrcv, msg.mtext+4);
pid_t pid = fork();
if (pid < 0)
ERR_EXIT("fork");
else if (pid == 0)
{
msg.mtype = MTYPE_GLOBAL;
msgsnd(clientMsgid, &msg, nrcv, IPC_NOWAIT);
memset(&msg, 0, sizeof(msg));
break;
}
memset(&msg, 0, sizeof(msg));
}
}
int main(int argc, char *argv[])
{
int msgid;
msgid = msgget(MSGQ_KEY, IPC_CREAT | 0666);
if (msgid == -1)
ERR_EXIT("msgget");
echo_ser(msgid);
return 0;
}
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#define ERR_EXIT(m) \
do { \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
#define MSGMAX 8192
#define MSGQ_KEY 1234
#define MTYPE_GLOBAL 1
struct Msgbuf
{
long mtype;
char mtext[MSGMAX];
};
void echo_cli(int msgidForWr, int msgidForRead)
{
int nrcv;
int pid = getpid();
struct Msgbuf msg;
memset(&msg, 0, sizeof(msg));
while (fgets(msg.mtext+4, MSGMAX, stdin) != NULL)
{
msg.mtype = MTYPE_GLOBAL;
*((int *)msg.mtext) = msgidForRead;
if (msgsnd(msgidForWr, &msg, 4 + strlen(msg.mtext + 4), IPC_NOWAIT) < 0)
ERR_EXIT("msgsnd");
if ((nrcv = msgrcv(msgidForRead, &msg, MSGMAX, MTYPE_GLOBAL, 0)) < 0)
ERR_EXIT("msgsnd");
fputs(msg.mtext + 4, stdout);
if (msg.mtext[4] == '\n') break;
memset(&msg, 0, sizeof(msg));
}
msgctl(msgidForRead, IPC_RMID, NULL);
}
int main(int argc, char *argv[])
{
int msgidForWr, msgidForRead;
msgidForWr = msgget(MSGQ_KEY, IPC_CREAT);
if (msgidForWr == -1)
ERR_EXIT("msgget");
msgidForRead = msgget(IPC_PRIVATE, 0666 | IPC_CREAT |IPC_EXCL);
if (msgidForWr == -1)
ERR_EXIT("msgget");
echo_cli(msgidForWr, msgidForRead);
return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)