Linux学习之进程通信(消息队列)

言之者无罪,闻之者足以戒。 ——《诗序》

消息队列:

链式队列:

msqid ds  维护消息队列的结构体,队列的第一个消息指针msg_first,最后一个消息指针msg_last

消息中有一个成员指针next

每一个消息中包含有哪些内容:

Data          数据

Length      数据的长度

Type          数据的类型

消息的接收端可以根据消息的类型来接收。

消息队列与文件IO的对比:

文件I/O

消息队列

open(打开文件)

msg_get(创建消息队列)       

read(读数据)

msgrcv(从消息队列中读数据)

write(写数据)

msgsnd(向消息队列中写数据)

close(关闭文件)

msgctl(删除消息对列)

1、msgget:创建消息队列

所需头文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函数原型

int msgget(key_t key, int flag);

函数参数

key:和消息队列关联的key值;可以用宏定义IPC_PRIVATE,也可以用ftok()函数

 

flag:消息队列的访问权限

函数返回值

成功:消息队列ID

 

出错:-1

2、msgctl:删除消息队列

所需头文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函数原型

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

函数参数

msqid:消息队列的队列ID

 

cmd:

IPC_STAT:读取消息队列的属性,并将其保存在buf指向的缓冲区中。

 

 

IPC_SET:设置消息队列的属性。这个值取自buf参数。

 

 

IPC_RMID:从系统中删除消息队列。

 

buf:消息队列缓冲区

函数返回值

成功:0

 

出错:-1

下面我们来看一下关于这两个函数的程序:

#include "sys/types.h"
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
int main()
{
        int msgid;
        msgid=msgget(IPC_PRIVATE,0777);
        if(msgid < 0)
        {
                printf("creat message queue failure\n");
                return -1;
        }
        printf("creat message queue sucess msgid=%d\n",msgid);
        system("ipcs -q");

        msgctl(msgid,IPC_RMID,NULL);
        system("ipcs -q");
        return 0;
}

3、msgsnd:向消息队列中写入数据

所需头文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函数原型

int msgsnd(int msqid, const void *msgp, size_t size, int flag);

函数参数

msqid:消息队列的ID

 

msgp:指向消息的指针。常用消息结构msgbuf如下:

struct msgbuf

{

    long mtype;          //消息类型

    char mtext[N]       //消息正文

}  

 

size:发送的消息正文的字节数

 

flag

IPC_NOWAIT  消息没有发送完成函数也会立即返回。

 

 

0:直到发送完成函数才返回

函数返回值

成功:0

 

出错:-1

4、msgrcv:从消息队列中读取数据

所需头文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函数原型

int msgrcv(int msgid,  void* msgp,  size_t  size,  long msgtype,  int  flag);

函数参数

msqid:消息队列的ID

 

msgp:接收消息的缓冲区

 

size:要接收的消息的字节数

 

msgtype

 0:接收消息队列中第一个消息。

 

 

大于0:接收消息队列中第一个类型为msgtyp的消息.

 

 

小于0:接收消息队列中类型值不大于msgtyp的绝对值且类型值又最小的消息。

 

flag

0:若无消息函数会一直阻塞

 

 

IPC_NOWAIT:若没有消息,进程会立即返回ENOMSG

函数返回值

成功:接收到的消息的长度

 

出错:-1

消息队列中数据读后,数据也不存在了

下面看一下程序:

#include "sys/types.h"
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include <string.h>
struct msgbuf
{
        long type;
        char voltage[124];
        char ID[4];
};
int main()
{
        int msgid;
        int readret;
        struct msgbuf sendbuf,recvbuf;
        msgid=msgget(IPC_PRIVATE,0777);
        if(msgid < 0)
        {
                printf("creat message queue failure\n");
                return -1;
        }
        printf("creat message queue sucess msgid=%d\n",msgid);
        system("ipcs -q");
        sendbuf.type=100;
        printf("please input message:\n");
        fgets(sendbuf.voltage,124,stdin);
        msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.voltage),0);
     
        memset(recvbuf.voltage,0,124);
        readret=msgrcv(msgid,(void *)&recvbuf,124,100,0);
        printf("recv:%s",recvbuf.voltage);
        printf("readret=%d\n",readret);

        msgrcv(msgid,(void *)&recvbuf,124,100,0);
        printf("second read after\n");
        msgctl(msgid,IPC_RMID,NULL);
        system("ipcs -q");
        return 0;
}

(1)下面我们用一个消息队列实现无亲缘关系的进程的单向通信:

write函数:

#include "sys/types.h"
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include <string.h>
struct msgbuf
{
        long type;
        char voltage[124];
        char ID[4];
};
int main()
{
        int msgid;
        int readret;
        struct msgbuf sendbuf,recvbuf;
        int key;
        key=ftok("./a.c",'a');
        if(key < 0)
        {
                printf("creat key failure\n");
                return -2;
        }
        msgid=msgget(key,IPC_CREAT | 0777);
        if(msgid < 0)
        {
                printf("creat message queue failure\n");
                return -1;
        }
        printf("creat message queue sucess msgid=%d\n",msgid);
        system("ipcs -q");
        sendbuf.type=100;
        while(1)
        {
           memset(sendbuf.voltage,0,124);//clear send buffer
           printf("please input message:\n");
           fgets(sendbuf.voltage,124,stdin);//input from key panel
           msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.voltage),0);
        }

        msgctl(msgid,IPC_RMID,NULL);
        system("ipcs -q");
        return 0;
}

read函数:

#include "sys/types.h"
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include <string.h>
struct msgbuf
{
        long type;
        char voltage[124];
        char ID[4];
};
int main()
{
        int msgid;
        int readret;
        struct msgbuf sendbuf,recvbuf;
        int key;
        key=ftok("./a.c",'a');
        if(key < 0)
        {
                printf("creat key failure\n");
                return -2;
        }
        msgid=msgget(key,IPC_CREAT | 0777);
        if(msgid < 0)
        {
                printf("creat message queue failure\n");
                return -1;
        }
        printf("creat message queue sucess msgid=%d\n",msgid);
        system("ipcs -q");
        sendbuf.type=100;
        while(1)
        {
           memset(recvbuf.voltage,0,124);//clear receive buffer
           msgrcv(msgid,(void *)&recvbuf,124,100,0);
           printf("receive data from message queue:%s",recvbuf.voltage);

        }

        msgctl(msgid,IPC_RMID,NULL);
        system("ipcs -q");
        return 0;
}

(2)用消息队列实现父子进程的双通信

server函数:

#include "sys/types.h"
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include <string.h>
struct msgbuf
{
        long type;
        char voltage[124];
        char ID[4];
};
int main()
{
        int msgid;
        int readret;
        int pid;
        struct msgbuf sendbuf,recvbuf;
        int key;
        key=ftok("./b.c",'a');
        if(key < 0)
        {
                printf("creat key failure\n");
                return -2;
        }
        msgid=msgget(key,IPC_CREAT | 0777);
        if(msgid < 0)
        {
                printf("creat message queue failure\n");
                return -1;
        }
        printf("creat message queue sucess msgid=%d\n",msgid);
        system("ipcs -q");
        pid=fork();
        if(pid > 0)//parent process write 100
        {
          sendbuf.type=100;
         //write message queue
          while(1)
          {
            memset(sendbuf.voltage,0,124);
            printf("please input message:\n");
            fgets(sendbuf.voltage,124,stdin);
            msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.voltage),0);
          }
        }
        if(pid == 0)//child process read 200
        {
           while(1)
           {
             memset(recvbuf.voltage,0,124);
             msgrcv(msgid,(void *)&recvbuf,124,200,0);
             printf("receive message from message queue:%s",recvbuf.voltage);
           }
        }
        msgctl(msgid,IPC_RMID,NULL);
        system("ipcs -q");
        return 0;
}

client函数:

#include "sys/types.h"
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include <string.h>
struct msgbuf
{
        long type;
        char voltage[124];
        char ID[4];
};
int main()
{
        int msgid;
        int readret;
        int pid;
        struct msgbuf sendbuf,recvbuf;
        int key;
        key=ftok("./b.c",'a');
        if(key < 0)
        {
                printf("creat key failure\n");
                return -2;
        }
        msgid=msgget(key,IPC_CREAT | 0777);
        if(msgid < 0)
        {
                printf("creat message queue failure\n");
                return -1;
        }
        printf("creat message queue sucess msgid=%d\n",msgid);
        system("ipcs -q");
        pid=fork();
        if(pid == 0)//child process write 200
        {
          sendbuf.type=200;
         //write message queue
          while(1)
          {
            memset(sendbuf.voltage,0,124);
            printf("please input message:\n");
            fgets(sendbuf.voltage,124,stdin);
            msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.voltage),0);
          }
        }
        if(pid > 0)//parent process read 100
        {
           while(1)
           {
             memset(recvbuf.voltage,0,124);
             msgrcv(msgid,(void *)&recvbuf,124,100,0);
             printf("receive message from message queue:%s",recvbuf.voltage);
           }
        }
        msgctl(msgid,IPC_RMID,NULL);
        system("ipcs -q");
        return 0;
}

上面的两个程序实现了父子进程的双通信;在server程序中父进程以type为100来发送数据,子进程以type为200来接收数据;在client程序中父进程以type为100来接收数据,子进程以type为200来发送数据。这样就实现了在一个消息队列中的双通信。

猜你喜欢

转载自blog.csdn.net/weixin_42994525/article/details/83090883