linux 进程间通信 消息队列

来源:互联网 发布:java中交换两个数 编辑:程序博客网 时间:2024/05/17 06:53

消息队列常用操作函数如下:

    #include <sys/msg.h>      #include <sys/types.h>      #include <sys/ipc.h>            key_t ftok(const char *pathname, int proj_id);      int msgget(key_t key, int msgflg);      int msgrcv(int msqid, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflg);      int msgsnd(int msqid, const void *msg_ptr, size_t msg_sz, int msgflg);      int msgctl(int msqid, int cmd, struct msqid_ds *buf);  

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

struct ipc_perm {    key_t          __key;       /* Key supplied to xxxget(2) */    uid_t          uid;         /* Effective UID of owner */    gid_t          gid;         /* Effective GID of owner */    uid_t          cuid;        /* Effective UID of creator */    gid_t          cgid;        /* Effective GID of creator */    unsigned short mode;        /* Permissions */    unsigned short __seq;       /* Sequence number */};struct msqid_ds {    struct ipc_perm msg_perm;     /* Ownership and permissions */    time_t         msg_stime;    /* Time of last msgsnd(2) */     time_t         msg_rtime;    /* Time of last msgrcv(2) */    time_t         msg_ctime;    /* Time of last change */    unsigned long    __msg_cbytes; /* Current number of bytes in                        queue (nonstandard) */    msgqnum_t         msg_qnum;     /* Current number of messages                                                            in queue */    msglen_t         msg_qbytes;   /* Maximum number of bytes                                                allowed in queue */    pid_t                      msg_lspid;      /* PID of last msgsnd(2) */    pid_t                  msg_lrpid;      /* PID of last msgrcv(2) */};


msgget函数 
功能:用来创建和访问一个消息队列
原型
int msgget(key_t key, int msgflg);
参数
key: 某个消息队列的名字
msgflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
返回值:成功返回一个非负整数,即该消息队列的标识码;失败返回-1


msgget函数参数关系图:



msgctl函数
功能:消息队列的控制函数
原型
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数
msqid: 由msgget函数返回的消息队列标识码
cmd:是将要采取的动作,(有三个可取值)
返回值:成功返回0,失败返回-1


msgsnd函数
功能:把一条消息添加到消息队列中
原型
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数
msgid: 由msgget函数返回的消息队列标识码
msgp:是一个指针,指针指向准备发送的消息,
msgsz:是msgp指向的消息长度,这个长度不含保存消息类型的那个long int长整型
msgflg:控制着当前消息队列满或到达系统上限时将要发生的事情
返回值:成功返回0;失败返回-1
msgflg=IPC_NOWAIT表示队列满不等待,返回EAGAIN错误。
消息结构在两方面受到制约。首先,它必须小于系统规定的上限值;其次,它必须以一个long int长整数开始,接收者函数将利用这个长整数确定消息的类型
消息结构参考形式如下:
struct msgbuf 

{
long  mtype;
char mtext[100];
}



msgrcv函数
功能:是从一个消息队列接收消息
原型
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数
msgid: 由msgget函数返回的消息队列标识码
msgp:是一个指针,指针指向准备接收的消息,
msgsz:是msgp指向的消息长度,这个长度不含保存消息类型的那个long int长整型
msgtype:它可以实现接收优先级的简单形式
msgflg:控制着队列中没有相应类型的消息可供接收时将要发生的事
返回值:成功返回实际放到接收缓冲区里去的字符个数,失败返回-1
msgtype=0返回队列第一条信息
msgtype>0返回队列第一条类型等于msgtype的消息 
msgtype<0返回队列第一条类型小于等于msgtype绝对值的消息,并且是满足条件的消息类型最小的消息


msgflg=IPC_NOWAIT,队列没有可读消息不等待,返回ENOMSG错误。
msgflg=MSG_NOERROR,消息大小超过msgsz时被截断 
msgtype>0且msgflg=MSG_EXCEPT,接收类型不等于msgtype的第一条消息。

msg01.c
#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#include <stdio.h>int main(int argc, char *argv[]){        int msg_id = msgget( 0x1234, 0666);        if(msg_id == -1)        {                printf("msgget error\n");                return -1;        }        return 0;}



msg02.c
#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#include <stdio.h>#include <errno.h>int main(int argc, char *argv[]){        int msg_id = msgget( 0x1234, 0666);        if(msg_id == -1)        {                printf("msgget error\n");                if(errno == ENOENT )                {                        printf("No message queue exists for key\n");                        return -1;                }        }        return 0;}

msg03.c

#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#include <stdio.h>#include <errno.h>int main(int argc, char *argv[]){        int msg_id = msgget( 0x1234, IPC_CREAT | 0666);        if(msg_id == -1)        {                printf("msgget error\n");                if(errno == ENOENT )                {                        printf("No message queue exists for key\n");                        return -1;                }        }        printf("get msg queue id = %d\n", msg_id);        struct msqid_ds mq;        if(msgctl(msg_id, IPC_STAT, &mq) != 0)        {                //printf("msgctl error\n");                perror("msgctl error:\n");                return -1;        }        int mode = mq.msg_perm.mode;        int curretSize = mq.__msg_cbytes;        int currentNumber = mq.msg_qnum;        printf("mode = %o, curretSize = %d, currentNumber = %d\n", mode, curretSize, currentNumber);        mq.msg_perm.mode = 0644;        if(msgctl(msg_id, IPC_SET, &mq) != 0)        {                perror("msgget err");                return -1;        }        return 0;}

msg04.c
#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#include <stdio.h>#include <errno.h>int main(int argc, char *argv[]){        int msg_id = msgget( 0x1234, IPC_CREAT | 0666);        if(msg_id == -1)        {                printf("msgget error\n");                if(errno == ENOENT )                {                        printf("No message queue exists for key\n");                        return -1;                }        }        printf("get msg queue id = %d\n", msg_id);        struct msqid_ds mq;        if(msgctl(msg_id, IPC_STAT, &mq) != 0)        {                //printf("msgctl error\n");                perror("msgctl error:");                return -1;        }        int mode = mq.msg_perm.mode;        int curretSize = mq.__msg_cbytes;        int currentNumber = mq.msg_qnum;        printf("mode = %o, curretSize = %d, currentNumber = %d\n", mode, curretSize, currentNumber);        if(msgctl(msg_id, IPC_RMID, NULL) != 0)        {                perror("msgctl error:");                return -1;        }        return 0;}


消息队列的简单应用:

消息队列实现回射客户/服务器




echoclient.c
#include <unistd.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#define ERR_EXIT(m) \        do \        { \                perror(m); \                exit(EXIT_FAILURE); \        } while(0)#define MSGMAX 8192struct msgbuf {long mtype;       /* message type, must be > 0 */char mtext[MSGMAX];    /* message data */};//思路://客户端发给服务器消息类型总是1//服务器端回给客户端的type是对方进程号//相当于服务器端 从消息队列中收消息,然后服务器端分类型回复客户端(通过消息队列)//n个进程通过消息队列进行交换//有没有产生死锁的可能//n个客户端向服务器发送消息(本质上是向内核消息队列发送消息),若消息队列满了;服务区回射时,会阻塞。。造成程序死锁//即使,非阻塞。。。仍然回阻塞。。void echo_cli(int msgid){int n;int pid;pid = getpid();struct msgbuf msg;memset(&msg, 0, sizeof(msg));//消息内容由:自己的pid+键盘输入*((int*)msg.mtext) = pid;//消息类型 1msg.mtype = 1;while (fgets(msg.mtext+4, MSGMAX, stdin) != NULL){if (msgsnd(msgid, &msg, 4+strlen(msg.mtext+4), 0) < 0)ERR_EXIT("msgsnd");//前四个字节是自己的pidmemset(msg.mtext+4, 0, MSGMAX - 4);if ((n = msgrcv(msgid, &msg, MSGMAX, pid, 0)) < 0)                        ERR_EXIT("msgsnd");fputs(msg.mtext+4, stdout);memset(msg.mtext+4, 0, MSGMAX-4);}}int main(int argc, char *argv[]){int msgid;msgid = msgget(0x1234, 0);if (msgid == -1)ERR_EXIT("msgget");echo_cli(msgid);return 0;}

echoserver.c
#include <unistd.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#define ERR_EXIT(m) \        do \        { \                perror(m); \                exit(EXIT_FAILURE); \        } while(0)#define MSGMAX 8192struct msgbuf {long mtype;       /* message type, must be > 0 */char mtext[MSGMAX];    /* message data */};void echo_srv(int msgid){int n;struct msgbuf msg;memset(&msg, 0, sizeof(msg));while (1){if ((n = msgrcv(msgid, &msg, MSGMAX, 1, 0)) < 0)ERR_EXIT("msgsnd");int pid;pid = *((int*)msg.mtext);fputs(msg.mtext+4, stdout);msg.mtype = pid;msgsnd(msgid, &msg, n, 0);}}int main(int argc, char *argv[]){int msgid;msgid = msgget(0x1234, IPC_CREAT | 0666);if (msgid == -1)ERR_EXIT("msgget");echo_srv(msgid);return 0;}


1 0
原创粉丝点击