1. 程式人生 > >Linux學習之程序通訊(五)

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來發送資料。這樣就實現了在一個訊息佇列中的雙通訊。