Linux进程IPC浅析[进程间通信SystemV消息队列]

Linux进程IPC浅析[进程间通信SystemV消息队列]

  1. System V IPC的概述
  2. System V IPC对象访问
  3. System V IPC消息队列

System V IPC的概述

System V Ipc概述:
1:Unix系统存在信号,管道和命名管道等基本通信机制
2:System V引入三种高级进程间通信机制

消息队列,共享内存和信号量

IPC对象存在于内核中而不是文件系统中,由用户控制释放,不像管道的释放由内核控制
3:IPC对象用过其标识符来引用和访问,所有IPC对象在内核空间中有唯一性表示ID,在用户空间中的唯一标识为key
Linux IPC继承来自System V Ipc

System V IPC对象访问

IPC对象是全部对象
可用ipcs,ipcrm等命令查看或删除
Linux进程IPC浅析[进程间通信SystemV消息队列]_第1张图片
从上面我们可以看到共享内存端.信号量数组和消息队列

每个IPC对象的都由get函数创建
msgget,shmget,semget调用get函数时必须制定关键字key

IPC对象的权限和所有者结构体:
struct ipc_perm{
    uid_t uid;
    gid_t gid;
    uid_t cuid;
    gid_t cgid;
    mode_t mode;//权限
    ......;
}

System V IPC消息队列

消息队列概述:

1:消息队列是内核中的一个链表
2:用户进程将数据传输到内核后,内核重新添加一些如用户ID,组ID,读写进程的ID和优先级等相关信息后并打成一个数据包成为消息
3:允许一个或者多个进程往消息队列中写消息和读消息,但一个消息只能被一个进程读取,读取完毕后就自动删除
4:消息队列具有一定的FIFO特性,消息可以按照顺序发送到队列中,也可以几种不同的方式从队列中读取,每个消息队列在内核中用一个唯一的IPC标识ID表示
5:消息队列的实现包括创建和打开消息队列,发送消息,读取消息,和控制消息队列四种操作

消息队列属性:

 消息队列的属性:
struct msgid_ds{
    struct ipc_perm msg_perm;//IPC对象的权限和所有者结构体
    msgqnum_t msg_qnum; //队列中的消息个数
    msglen_t msg_qbytes; //队列中最大的字节数
    pid_t msg_lspid; //最后一个消息发送者的pid
    pid_t msg_lrpid; //最后一个消息接受者的pid
    time_t msg_stime; //最后发送的时间
    time_t msg_ctime; //消息队列最后改变的时间
    ......
}

消息队列函数:

打开或者创建消息队列

#include
int msgget(key_t key,int flag);
返回:成功返回内核中消息队列的表示ID,出错返回-1(不存在则创建,存在则打开)
参数:
    key:用户指定的消息队列健值
    flag:IPC_CREAT,IPC_EXCL等权限组合(IPC_CREATE | IPC_EXCL |0777)
    注意:若创建消息队列,key可制定健值,也可将之设置为
    IPC_PRIVATE.若打开进行查询,则key不能为0必须是一个非0的值否则查询不到;

消息队列的控制函数:

#include
int msgctl(int msgid,int cmd,struct msqid_ds *buf);
返回:成功返回0,出错返回-1
参数:
    msgid:消息队列ID
    buf:消息队列属性指针
    cmd(有很多):
        IPC_STAT获取消息队列的属性,取此队列的msqid_ds结构,并将其存放在buf指向的结构中去
        IPC_SET:设置属性,按有buf指向的结构中的值,设置与此队列相关的结构中的字段
        IPC_RMID:删除队列,从系统中删除该消息队列以及仍在该队列上的所有数据

消息队列的发送函数:

消息队列的发送:
#include
int msgsnd(int msgqid,const void *ptr,size_t nbytes,int flag);
返回:成功返回0,出错返回-1
-------------
参数ptr:
struct mymesg{
    long mtype; //消息类型
    char mtext[512] //消息数据的本身
}
    mtype指的是消息的类型,它由一个证书来代表,并且它只能是大于0的整数
mtext是消息数据的本身(文本或者二进制类型都可以)
在Linux中,消息的最大长度是4056个字节,其中包括mtype,它占有4个字节
结构体mymesg用户可自定义,但是第一个成员必须是mtype
-------------
参数nbytes: 
    指定消息的大小,不包括mtype的大小,也就是仅仅只是消息本身的大小(sizeof(struct mymesg) - sizeof(long))

参数flag:
    0:阻塞
    IPC_NOWAIT:类似与文件I/O的非阻塞状态
    若消息队列已经满了(或者是队列中的消息总数等于系统限制值,或队列中的字节总数等于系统限制值):
    指定IPC_NOWAIT
        使得msgsnd立即出错返回EAGAIN,
    如果指定0,则进程
        阻塞直到有空间可以容纳要发送的消息
        或从系统中删除了此队列
        或捕捉到一个信号,并且从信号处理程序返回

消息队列的接受

#include
ssize_t msgrcv(int msgqid,void *ptr,size_t nbytes,long type,int flag);
返回:成功返回消息的数据部分长度,出错返回-1
参数:
    msgqid:消息队列ID
    ptr:指向存放消息的缓存
    nbytes:消息缓存的大小,不包括mtype的大小,计算方式:nbytes = sizeof(struct mymesg) - sizeof(long)如果大小不对,那么可能不能获取完整的消息;
    type:消息类型
        type==0 :获得消息队列中的第一个消息
        type>0:获得消息队列中类型为type的第一个消息
        type<0:获得消息队列中小于或等于type绝对值的消息
    flag:0或者IPC_NOWAIT

直接上代码,msg_send

/*
 * ===========================================================================
 *
 *       Filename:  msg_send.c
 *    Description:  消息的发送
 *        Version:  1.0
 *        Created:  2017年04月10日 21时54分13秒
 *       Revision:  none
 *       Compiler:  gcc
 *         Author:   (), 
 *        Company:  
 *
 * ===========================================================================
 */

#include
#include
#include
#include

#define BUFFER 1024

typedef struct{
  long type;
  char content[BUFFER];
}MSG;



int main(int argc,char * argv[]){
  if(argc < 2){
    printf("缺少参数");
    exit(EXIT_FAILURE);
  } 
  //传入的字符串转换为整形
  key_t key = atoi(argv[1]);
  printf("key:%d\n",key);

  int msg_id;
  //第一次是创建,第二次是获取
  if((msg_id = msgget(key,IPC_CREAT|IPC_EXCL|0777)) < 0){
      printf("msg error\n");
  }

  MSG msg1 = {1,"hello"};
  MSG msg2 = {2,"world"};
  MSG msg3 = {5,"nihao"};
  MSG msg4 = {7,"woshizzf"};

  if(msgsnd(msg_id,&msg1,sizeof(MSG)-sizeof(long),IPC_NOWAIT) != 0){
      printf("send msg1 error\n");
  }

  if(msgsnd(msg_id,&msg2,sizeof(MSG)-sizeof(long),IPC_NOWAIT) != 0){
      printf("send msg2 error\n");
  }

  if(msgsnd(msg_id,&msg3,sizeof(MSG)-sizeof(long),IPC_NOWAIT) != 0){
      printf("send msg3 error\n");
  }

  if(msgsnd(msg_id,&msg4,sizeof(MSG)-sizeof(long),IPC_NOWAIT) != 0){
      printf("send msg4 error\n");
  }

  struct msqid_ds ds;
  if(msgctl(msg_id,IPC_STAT,&ds) != 0){
     perror("msgctl error");
  }

  printf("msg total:%ld\n",ds.msg_qnum);

  printf("msg id:%d\n",msg_id);


  return 0;
}

msg_get.c

/*
 * ===========================================================================
 *
 *       Filename:  msg_get.c
 *    Description:  
 *        Version:  1.0
 *        Created:  2017年04月10日 22时33分28秒
 *       Revision:  none
 *       Compiler:  gcc
 *         Author:   (), 
 *        Company:  
 *
 * ===========================================================================
 */

#include
#include
#include
#include
#define BUFFER 1024

typedef struct{
  long type;
  char content[BUFFER];
}MSG;

int main(int argc ,char * argv[]){
  if(argc < 3){
      printf("参数错误");
      exit(EXIT_FAILURE);
  }

  key_t key = atoi(argv[1]);
  long type = atoi(argv[2]);

  printf("key:%d,type:%ld\n",key,type);
  int msg_id;
  if((msg_id = msgget(key,0777)) < 0){
    perror("get msg error");
  }

  printf("msg_id:%d\n",msg_id);
  MSG m;
  if(msgrcv(msg_id,&m,sizeof(MSG)-sizeof(long),type,IPC_NOWAIT) < 0){
      perror("get msg error\n");
  }else{
    printf("msg get type:%ld,content:%s\n",m.type,m.content);
  }

  return 0;
}

以上就是很简单的关于消息队列的调试代码.很简单.欢迎补充

欢迎持续访问博客

你可能感兴趣的:(#,2:LinuxC学习,#,1:C语言之美,linux,消息队列,进程通信,SystemV消息)