linux 进程间通信——消息队列

使用方法

  1. 构造消息结构体
#define MAX_LEN	1020
struct msg_node
{
	long msg_type;
	char msg_data[MAX_LEN];
};
  1. 使用有效文件或文件夹路径得到一个键值
#include <sys/types.h>
#include <sys/ipc.h>

key_t ftok(const char *pathname, int proj_id);
	错误返回 -1

//1. ftok函数会先的到pathname的stat结构体,
//2. 将proj_id的 低8bit 和stat.st_dev的 低12bit 以及stat.st_ino的低 12bit 按高位到低位的顺序组合到以起
  1. 使用key值得到消息队列的id
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);
	错误返回 -1
  1. 填充数据到结构体中,并发送和接收
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

struct msg_node msg;
msg.msg_type = type;
memcpy(&(msg.msg_data), data, strlen(data));

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

msgflag: 0 或 IPC_NOWAIT
  1. msgctl
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

DESCRIPTION
   msgctl() performs the control operation specified by cmd on the System V message queue with identifier msqid.
   
   The msqid_ds data structure is defined in <sys/msg.h> as follows:
   
    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) */
	};
	 
    The ipc_perm structure is defined as follows (the highlighted fields are settable using IPC_SET):
    struct ipc_perm {
	     key_t          __key;       /* Key supplied to msgget(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 */
	    };
   Valid values for cmd are:
   IPC_STAT
    Copy information from the kernel data structure associated with msqid into the msqid_ds structure pointed to by buf.  The caller must have read permission on the message queue.
    
   IPC_SET
    Write  the  values  of some members of the msqid_ds structure pointed to by buf to the kernel data structure associated with this message queue, updating also its msg_ctime member.  The
    following members of the structure are updated: msg_qbytes, msg_perm.uid, msg_perm.gid, and (the least significant 9 bits of) msg_perm.mode.  The effective UID of  the  calling  process
    must match the owner (msg_perm.uid) or creator (msg_perm.cuid) of the message queue, or the caller must be privileged.  Appropriate privilege (Linux: the CAP_SYS_RESOURCE capability) is
    required to raise the msg_qbytes value beyond the system parameter MSGMNB.
    
   IPC_RMID
    Immediately remove the message queue, awakening all waiting reader and writer processes (with an error return and errno set to EIDRM).  The calling process must have appropriate  privi‐
    leges or its effective user ID must be either that of the creator or owner of the message queue.  The third argument to msgctl() is ignored in this case.

学习源码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define DEBUG
#define MAX_LEN 80

struct msg_body
{
 long mtype;
 char msg_data[MAX_LEN];
};
typedef struct msg_body msg_t;
enum msg_error
{
 SUCCESS = 0,
 PARA_ERR,
 SEND_ERR,
 NONE_MSG,
 RECV_ERR,
 DATA_LONG,
 MSGID_ERR,
 DEBUG_ERR
};
int msg_err(int error, int line)
{
#ifdef DEBUG
 fprintf(stderr, "---%d---\n", line);
#endif

 switch(error)
 {
  case PARA_ERR:
   fprintf(stderr, "parament is NULL\n");
   break;
  case SEND_ERR:
   fprintf(stderr, "send data error\n");
   break;
  case NONE_MSG:
   fprintf(stderr, "no message in queue\n");
   break;
  case RECV_ERR:
   fprintf(stderr, "receive data error\n");
   break;
  case DATA_LONG:
   fprintf(stderr, "data is too long\n");
   break;
  case MSGID_ERR:
   fprintf(stderr, "get msg id error\n");
   break;
  case DEBUG_ERR:
   break;
  default:
   fprintf(stderr, "unrecognized error\n");
 }
 return error;
}
int msg_usage(char *err)
{
 if(err == NULL)
  return 0; 
  
 fprintf(stderr, "error : %s\n", err);
 
 fprintf(stderr, "Usage: msg [option]\n");
 fprintf(stderr, "option args\n");
 fprintf(stderr, "-s   write message using msgsnd\n");
 fprintf(stderr, "-r   read message using msgrcv\n");
 fprintf(stderr, "-d   want to send message data, it must follow -s\n");
 fprintf(stderr, "-t   message type(default is 1)\n");
 fprintf(stderr, "-k   message queue key(default is 1234)\n");
 exit(EXIT_FAILURE);
}

int send_msg(int msg_id, msg_t *msg)
{
 if(msg_id < 0 || msg == NULL)
 {
  printf("msg_id = %d\n", msg_id);
  return msg_err(PARA_ERR, __LINE__);
 }
 
#ifdef DEBUG
    fprintf(stderr, "mtype = %ld\n", msg->mtype);
    fprintf(stderr, "msg_id = %ld\n", msg_id);
    fprintf(stderr, "msg_data = %s\n", msg->msg_data);
#endif

 if(0 > msgsnd(msg_id, (void *)msg, MAX_LEN, IPC_NOWAIT))
 {
  return msg_err(SEND_ERR, __LINE__);
 }
 
 fprintf(stderr, "send msg successful...\n");
 return 0;
}

int recv_msg(int msg_id, msg_t *msg)
{
 if(msg_id < 0 || msg == NULL)
 {
  printf("msg_id = %d\n", msg_id);
  return msg_err(PARA_ERR, __LINE__);
 }
 
#ifdef DEBUG
    fprintf(stderr, "mtype = %ld\n", msg->mtype);
    fprintf(stderr, "msg_id = %ld\n", msg_id);
#endif

 if(-1 == msgrcv(msg_id, (void *)msg, MAX_LEN, msg->mtype, MSG_NOERROR | IPC_NOWAIT))
 {
  if(errno == ENOMSG)
  {
   return msg_err(NONE_MSG, __LINE__);
  }
  return msg_err(RECV_ERR, __LINE__);
 }
 
 fprintf(stderr, "get msg is  %s\n", msg->msg_data);
 return 0;
}

int main(int argc, char **argv)
{
 int  ret = 0;
 msg_t msg;
 int  mode = 0;
 int  key = 1234; 
 int  msgid = 0;
 int  mtype = 1;
 int  opt = 0;
 int  len = 0;
 
 memset(&msg, 0, sizeof(msg_t));
 msg.mtype = mtype;
 
 while(-1 != (opt = getopt(argc, argv, "srd:t:k:")))
 {
  switch(opt)
  {
   case 's':
    mode = 1;
    break;
   case 'r':
    mode = 2;
    break;
   case 'd':
    if(mode != 1)
     msg_usage("-d must at -s later\n");
    if((len = strlen(optarg)) > MAX_LEN - 1)
     return msg_err(DATA_LONG, __LINE__);
    memcpy(&(msg.msg_data), optarg, len);
    break;
   case 't':
    msg.mtype = atoi(optarg);
    break;
   case 'k':
    key = atoi(optarg);
    break;
   default:
    fprintf(stderr, "Unknow opt\n");
    exit(EXIT_FAILURE);
  }
 }
 if(mode == 0)
  msg_usage("must use either -s or -r\n");
  
 if(0 > (msgid = msgget(key, IPC_CREAT | 0666)))
  return msg_err(MSGID_ERR, __LINE__);
  
#ifdef DEBUG
 fprintf(stderr, "mtype = %ld\n", msg.mtype);
 fprintf(stderr, "msg_id = %d\n", msgid);
#endif

 if(mode == 1)
  send_msg(msgid, &msg);
  
 if(mode == 2)
  recv_msg(msgid, &msg);
 return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值