您的位置:首页 > 运维架构 > Linux

msgget();msgsnd();msgrcv();msgctl(); 消息队列 Linux进程间的通信方式之消息队列

2012-04-25 22:41 483 查看
Linux进程间的通信方式 -———消息队列。

消息队列和共享内存类似

消息队列它允许一个或多个进程向它写消息,一个或多个进程向它写读消息。

消息队列存在于系统内核中,消息的数量受系统限制。

我们来看一下有关消息队列的函数。

msgget();msgsnd();msgrcv();msgctl();

第一个函数:

#include<sys/msg.h>

int msgget(key_t    key,int   msgflg);

功能:创建一个消息队列或取得一个已经存在的消息队列。

返回值:成功返回消息队列的标示符(ID),失败为-1;

参数:

 _key :

1.      
消息队列的键值,为IPC_PRIVATE  意思就是创建一个只能被创建进程读写的消息队列。

2.      
不是IPC_PRIVATE .则我们可以指定一个值6666,还可以用ftok();函数来获得一个唯一的键值。(ftok()函数见其它文章);

_msgflg : 创建消息队列的创建方式或权限。

     创建方式有:IPC_CREAT
如果内存不存在则创建一个消息队列,否则取得。

                 IPC_EXCL
只有不消息队列存在的时候,新的消息队列才会被创建,否则会产生错误。

 

Ok,看个例子:

 

#include<stdio.h>

#include<stdlib.h>

#include<sys/msg.h>

#define MYMSG_KEY 6666

int main(int argc ,char *argv[])

{

        int msgid;

        msgid=msgget(ftok(".",100),IPC_CREAT | 0644);

        //msgid=msg(MYMSG_KEY,IPC_CREAT | 0644);

        printf("msgid=%d\n",msgid);

        if(msgid==-1)

        {

                perror("msgget error :");

                exit(EXIT_FAILURE);

        }

 

        return 0;

}

运行结果如下:

 



我们可以用ipcs  -q  
来查看是否创建成功。

用ipcrm    –q   msgid号

 

 

==========================================================================

第二个函数:

#include<sys/msg.h>

 

Int msgsnd(int msgid,struct  msgbuf   *msgp ,int   msgsz,   int  msgflg);

功能:往队列中发送一个消息。

返回值:成功返回0,失败返回-1;

参数:

 msgid  消息表识id
也就是msgget()函数的返回值。

msgp   :指向消息缓冲区的指针,该结构体为

struct mymesg {
      long  mtype;      /* positive message type  消息的类型*/
      char  mtext[512]; /* message data, of length nbytes  存放消息数据内容*/
};
msgsz, :是消息的字节大小,不包含消息类型的长度(4个字节)
msgflg   :可以设置为0;或者使用IPC_NOWAIT,如果消息队列已经满了,那么次消息就不会写到消息队列中, 控制将返回到对于进程中。如果没有指明,调用进程会被挂起,直到消息可以写到消息队列中。

 

看一个一个例子:

  

#include<stdio.h>

#include<stdlib.h>

#include<sys/msg.h>

#include<string.h>

#define MYMSG_KEY 6666

 

struct mymesg {

        long  mtype;      /* positive message type */

        char  mtext[512]; /* message data, of length nbytes */

};

 

int main(int argc ,char *argv[])

{

        int msgid,msgsend_ret;

        char buf[25];

        struct  mymesg msg_send;

        msgid=msgget(ftok(".",100),IPC_CREAT | 0644);

        //msgid=msg(MYMSG_KEY,IPC_CREAT | 0644);

        printf("msgid=%d\n",msgid);

        if(msgid==-1)

        {

                perror("msgget error :");

                exit(EXIT_FAILURE);

        }

 

        // write messages to msg queue

        msg_send.mtype=1;

        printf("enter a message:\n");

        gets(buf);

        strcpy(msg_send.mtext,buf);

        msgsend_ret=msgsnd(msgid,&msg_send,strlen(msg_send.mtext)+1,0);

        if(msgsend_ret==-1)

        {

                perror("msgget error: ");

                exit(EXIT_FAILURE);

        }

           return 0;

}        

运行结果:在此我们写入2个消息

 



 我们可以看到消息的数量为2  

==================================================================

既然我们向消息队列中写入了那么我们就可以读取消息队列中的消息了。

那就要用到msgrcv();

格式:#include<sys/msg.h>

   int msgrcv(int  msgid ,  struct   msgbuf   *msgp,int  msgsz , long  mtype,int  msgflg );     

功能:   读取消息,从消息队列中读走消息,是读走不是读取,也就是读完之后没有了,这种机制类似于管道。  

返回值:成功返回0,失败返回-1;

参数:

msgid :  消息队列的id号

 msgp :是我们要读到的消息数据存储消息的地址。

msgsz  是消息的长度不包含mtype
的长度 ,我们可以这样算:

      msgsz=sizeof(struct   msgbuf)-sizeof(long);

mtype  是我们要从消息队列中读取的消息的类型。如果此值为0,则会读取时间最长的那一条消息,不论是什么类型,也就是我们第一个写入消息队列中的消息。

msgflg  可以设置为0,代表该进程将一直阻塞,直到有消息可读停止。但我们可以吧该值设为IPC_NOWAIT 
表示,如果没有消息可读时,则立刻返回-1,进程被挂起。

 

看例子:

     我们把刚才写的2个消息在读出来。

#include<stdio.h>

#include<stdlib.h>

#include<sys/msg.h>

#include<string.h>

#define MYMSG_KEY 6666

 

struct mymesg {

        long  mtype;      /* positive message type */

        char  mtext[512]; /* message data, of length nbytes */

};

 

int main(int argc ,char *argv[])

{

        int msgid,msgsend_ret;

        char buf[25];

        struct  mymesg msg_send;

        msgid=msgget(ftok(".",100),IPC_CREAT | 0644);

        //msgid=msg(MYMSG_KEY,IPC_CREAT | 0644);

        printf("msgid=%d\n",msgid);

       if(msgid==-1)

        {

                perror("msgget error :");

                exit(EXIT_FAILURE);

        }

 

        // write messages to msg queue

 /* 0   msg_send.mtype=1;

        printf("enter a message:\n");

        gets(buf);

        strcpy(msg_send.mtext,buf);

        msgsend_ret=msgsnd(msgid,&msg_send,strlen(msg_send.mtext)+1,0);

        if(msgsend_ret==-1)

        {

                perror("msgget error: ");

                exit(EXIT_FAILURE);

        }

*/

 

        //read mseeags from msg queue

        int msgrcv_ret;

        struct mymesg  mymsgrece;

        msgrcv_ret=msgrcv(msgid,&mymsgrece, sizeof(struct mymesg)-sizeof(long),1,0);

//读取消息的类型为1,长度为sizeof(struct mymesg)-sizeof(long)把读到

//的消息放到mymsgrece这这结构体中。

        if(msgrcv_ret==-1)

        {

                perror("msgrcv  error:");

                exit(EXIT_FAILURE);

        }

        printf("received msg  from  queue  : %s\n",mymsgrece.mtext);

 

 

        return 0;

}

                                  

 

运行结果:我们执行两次,把两个刚才写的两个消息都读出来。



 

从结果中我们看得出:  

1.      
先写进去的先读出来,即遵循先进先出的原则。

2.      
当我们尝试再去读时,它会阻塞。

3.      
用ipcs  -q查看她真是遵循读走就没有了的原则。

==========================================================

第四个函数,既消息队列进行处理函数,比如删除消息队列。

还可以进行获取消息队列的详细信息,改变消息队列的信息等。

格式:

 

 #include<sys/msg.h>

int  msgctl(int  msgid,  int  cmd  ,struct   msgqid _ds    *buf);

功能:对消息队列的控制处理函数。

返回值:成功返回0,失败返回-1.

参数:

 msgid   消息队列的ID,也就是msgget()函数的返回值。

cmd   命令,对消息队列的处理

     IPC_RMID  从系统内核中删除消息队列,相当于我们在终端输入ipcrm   -q 
消息队列id

IPC_STAT  获取消息队列的详细消息。包含权限,各种时间,id等

IPC_SET   设置消息队列的信息。

 

buf: 存放消息队列状态的结构体的地址。

 

看个例子:

#include<stdio.h>

#include<stdlib.h>

#include<sys/msg.h>

#include<string.h>

#define MYMSG_KEY 6666

 

int main(int argc ,char *argv[])

{

        int msgid,msgctl_ret;

        msgid=msgget(ftok(".",100),IPC_CREAT | 0644);

        //msgid=msg(MYMSG_KEY,IPC_CREAT | 0644);

        printf("msgid=%d\n",msgid);

        if(msgid==-1)

        {

                perror("msgget error :");

                exit(EXIT_FAILURE);

        }

 

         //delete queue

      /*      msgctl_ret = msgctl(msgid,IPC_RMID,0);

                if(msgctl_ret==-1)

                {

                perror("msgctl error :");

                exit(EXIT_FAILURE);

                }

                printf("deleted  queue %d ok.\n ",msgid);

         */

        return 0;

}

               

我们先把msgct函数注释,创建出一个消息队列,然后把创建的注释,启用msgct函数。

运行结果如下:

                  

 


我们把第二个参数改成IPC_STAT 
获取消息队列的详细消息。包含权限,各种时间,id等

例子:

 

#include<stdio.h>

#include<stdlib.h>

#include<sys/msg.h>

#include<string.h>

#define MYMSG_KEY 6666

struct mymesg {

        long  mtype;      /* positive message type */

        char  mtext[512]; /* message data, of length nbytes */

};

 

void msg_stat(int msgid,struct msqid_ds  msg_info)

{

        int ret;

        ret = msgctl(msgid,IPC_STAT,&msg_info);

        if(ret==-1)

        {

                perror("msgctl error :");

                exit(EXIT_FAILURE);

        }

        printf("\n");

        printf("current number of bytes on queue is %d\n",msg_info.msg_cbytes);

        printf(" max  of bytes on queue id %d\n",msg_info.msg_qbytes);

        printf(" number of messages in queue is %d\n",msg_info.msg_qnum);

        printf("last change time  is %s\n",ctime(&msg_info.msg_ctime));

        printf("message uid is  %d\n",msg_info.msg_perm.uid);

        printf("message gid is  %d\n",msg_info.msg_perm.gid);

 

}

 

int main(int argc ,char *argv[])

{

        char buf[25];

        int msgid,msgsend_ret,msgctl_ret;

        struct  mymesg msg_send;

        msgid=msgget(ftok(".",100),IPC_CREAT | 0644);

        //msgid=msg(MYMSG_KEY,IPC_CREAT | 0644);

        printf("msgid=%d\n",msgid);

        if(msgid==-1)

        {

                perror("msgget error :");

                exit(EXIT_FAILURE);

        }

 

        // write messages to msg queue

        msg_send.mtype=1;

        printf("enter a message:\n");

        gets(buf);

        strcpy(msg_send.mtext,buf);

        msgsend_ret=msgsnd(msgid,&msg_send,strlen(msg_send.mtext)+1,0);

        if(msgsend_ret==-1)

        {

                perror("msgget error: ");

                exit(EXIT_FAILURE);

        }

 

        struct msqid_ds  msg_ginfo;

        msg_stat(msgid,msg_ginfo);     

         return 0;

}   

 

运行结果:

    

 


Ok.我们综合用一下这4个函数

 msgget() 
类似文件操作函数open();

msgsnd();         类似文件操作函数write();

msgrcv ();         类似文件操作函数read();

 

msgctl();         类似文件操作函数close();

 

模拟银行的取号系统:

 源程序1(取号机);

#include<stdio.h>
#include<stdlib.h>
#include<sys/msg.h>
#include<string.h>
 
#define MYMSG_KEY  6666
 
struct mymesg {
    long  mtype;      /* positive message type */
    char  mtext[512]; /* message data, of length nbytes */
};
 
int main()
{
    int msgid,msgsend;
    struct  mymesg   mymsgsend;
    msgid=msgget(MYMSG_KEY,IPC_CREAT|0644);
    printf("msgid=%d\n",msgid);
    if(msgid==-1)
    {
       perror("msgget error: ");
       exit(EXIT_FAILURE);
    }
 
    mymsgsend.mtype=1;
    while(1)
    {
                printf("enter a  type  and a msg use to send :\n");
       scanf("%d%s",&mymsgsend.mtype,mymsgsend.mtext);
       msgsend=msgsnd(msgid,&mymsgsend,strlen(mymsgsend.mtext)+1,0);
       if(msgsend==-1)
       {
           perror("msgget error: ");
           exit(EXIT_FAILURE);
       }
              if(strcmp(mymsgsend.mtext,"exit")==0)  break;
 
    }
    return 0;
}
 
源程序2(综合业务):

#include<stdio.h>
#include<stdlib.h>
#include<sys/msg.h>
#define MYMSG_KEY 6666
 
struct mymesg {
    long  mtype;      /* positive message type */
    char  mtext[512]; /* message data, of length nbytes */
};
 
 
int main()
{
    int msgid,msgrcv_ret,msgctl_ret;
    struct mymesg  mymsgrece;
    msgid=msgget(MYMSG_KEY ,IPC_CREAT|0644);
    printf("msgid=%d\n",msgid);
    if(msgid==-1)
    {
       perror("msgget error:");
       exit(EXIT_FAILURE);
    }
    while(1)
    {
                scanf("%d",&mymsgrece.mtype);
       msgrcv_ret=msgrcv(msgid,&mymsgrece,512,mymsgrece.mtype,0);

       if(msgrcv_ret==-1)
       {
           perror("msgrcv  error:");
           exit(EXIT_FAILURE);
       }
               if(strcmp(mymsgrece.mtext,"exit")==0)  break;
          printf("received msg : %s\n",mymsgrece.mtext);
    }
    msgctl_ret=msgctl(msgid,IPC_RMID,0);
    if(msgctl_ret==-1)
    {
       perror("msgrcv  error:");
       exit(EXIT_FAILURE);
    }
    return 0;
}
 
 

运行结果:

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux struct cmd 终端 存储