linux 进程间通信 消息队列

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

    #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 8192
struct 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;
	//消息类型 1
	msg.mtype = 1;
	
	while (fgets(msg.mtext+4, MSGMAX, stdin) != NULL)
	{
		if (msgsnd(msgid, &msg, 4+strlen(msg.mtext+4), 0) < 0)
			ERR_EXIT("msgsnd");

		//前四个字节是自己的pid
		memset(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 8192
struct 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值