1. 程式人生 > >Linux c 基於記憶體的程序通訊—共享記憶體、共享佇列(訊息佇列)

Linux c 基於記憶體的程序通訊—共享記憶體、共享佇列(訊息佇列)

基於記憶體的程序通訊:

1.      核心共享記憶體

程式設計模型:

 1.1.建立共享記憶體,得到一個ID  shmget

1.2.把ID影射成虛擬地址(掛載)  shmat

       1.3.使用虛擬地址訪問核心共享記憶體使用任何記憶體函式與運算子號                        1.4.解除安裝虛擬地址 shmdt

       1.5.刪除共享記憶體 shctl(修改/獲取共享記憶體的屬性)

案例:

A.建立共享記憶體,並且修改記憶體資料

1.      建立共享記憶體

                              #include<sys/shm.h>

                              intshmget(key_t key,//為什麼需要key

                                                                       int size,//共享記憶體大小

                                                                       int flags//共享記憶體的屬性與許可權

                                                 )

                                          為什麼要key_t:

                                                        約定建立與訪問的是同一個共享記憶體。Key為兩個程序之間訪問同一塊共享記憶體的約定

注:key需要唯一性,因為我們不能保證我們自己定義的key的唯一性,所以為了保證kay的唯一性,我們需要用某個檔案對應的整數來充當kay值,可以用ftok函式來將一個檔案轉化為一個kay值。(一般我們用兩個程序的共同的工程目錄檔案來確定kay值)

                         ftok函式:

                                  #include<sys/ipc.h>

                                   key_t   ftok( const char * pathname,int  proj_id);

                                   引數二:一個控制因子。建議在0—255之間

                                          第三個引數:

                                                               方式|許可權

                                                               方式:建立 IPC_CREAT  IPC_EXCL(如果記憶體已經建立,直接錯誤返回)

                                                               開啟:0

                                                        常見的兩種方式:

                                                                      建立:IPC_CREAT|IPC_EXCL | 0666;

                                                                      開啟:0

                                   返回:

                                                 成功返回共享記憶體ID

                                                 失敗返回-1                 

                            失敗返回-1                 

                     B.根據ID得到共享記憶體,並且訪問記憶體資料。

                                   掛載共享記憶體

void* shmat(int id,

                                                 void*startaddr,//0:系統指定首地址

                                                 intflags)//掛載方式,建議0預設讀寫,可以使用IPC_RDONLY

                             返回值:合法地址成功,-1失敗

                     C.刪除

                                   intshmctl(int id,//被操作的共享記憶體ID

                                                 inthow,//操作方式:一共三種操作

                                                 structshmid_ds*ds)//共享記憶體屬性

                                   how:

                                                 IPC_STAT   

                                                 IPC_SET     //修改屬性

                                                 IPC_RMID   //刪除   引數三無用

案例程式碼:

ShmA.c

#include<stdio.h>

#include<stdlib.h>

#include<signal.h>

#include<sys/shm.h>

#include<sys/ipc.h>

void   main()

{

      key_t   key;

      int     shmid;

      int * p;

      //1.建立共享記憶體

      key=ftok( “.” , 255 );   //用當前路徑的目錄來確定kay值

      if(key == -1)  printf(“ftok error%m\n”) ,  exit( - 1 );

      shmid=shmget( key , 4 , IPC_CREAT|IPC_EXCL | 0666 );

      if(shmid == -1) printf(“shmget error %m\n”) , exit( -1 );

      //2.掛載共享記憶體

      p=shmat( shmid , 0 , 0);

      if(p==(int *) - 1) printf(“at error %m\n”) , exit( -1 );

      //3.訪問共享記憶體

      *p=999;

      //4.解除安裝共享記憶體

      shmdt(shmid);

      //刪除共享記憶體

      shctl( shmid , IPC_RMID , 0);

}

不建立共享記憶體,只訪問已有的

shmB.c

ShmA.c

#include<stdio.h>

#include<stdlib.h>

#include<signal.h>

#include<sys/shm.h>

#include<sys/ipc.h>

void   main()

{

      key_t   key;

      int     shmid;

      int * p;

      //1.得到共享記憶體

      key=ftok( “.” , 255 );   //用當前路徑的目錄來確定kay值

      if(key == -1)  printf(“ftok error%m\n”) ,  exit( - 1 );

      shmid=shmget( key , 4 ,0 );

      if(shmid == -1) printf(“shmget error %m\n”) , exit( -1 );

      //2.掛載共享記憶體

       p=shmat( shmid , 0 , 0);

      if(p==(int *) - 1) printf(“at error %m\n”) , exit( -1 );

      //3.訪問共享記憶體

      printf(“%d\n”,*p);

      //4.解除安裝共享記憶體

      shmdt(shmid);

}

2.      核心共享佇列(有序)

        程式設計模型:

                                          2.1.建立共享佇列/得到佇列msgget

                                          2.2.使用佇列(傳送訊息msgsnd/接收訊息msgrcv)

                                          2.3.刪除佇列msgctl

案例:

                     建立共享佇列

           #include<sys/msg.h>

                                   intmsgget(key_t,int); 除了不用指定大小,和shmget函式的引數一樣                             

                     傳送訊息

                                   intmsgsnd(

                                                 intid,//訊息佇列ID

                                                 constvoid *msg,//要傳送訊息

                                                 size_tlen,//訊息的長度

                                                 int flags//傳送訊息的方式,建議為0

                                          );

                                   返回:

                                                 -1:失敗

                                                  0:成功  

                                   第二個引數的訊息有固定的格式

                                                        4位元組:表示訊息的型別

                                                        若干位元組:訊息內容。

                     訊息格式:(該結構體需要我們自己定義)

                              struct  msgbuf{

                                   long   mtype; //訊息型別

                                   char   mtext[1]; //訊息內容

                              }

                                   第三個引數:

                                                        訊息的大小,不包含型別的4個位元組

              接收訊息:

                       size_t   msgrcv(int id ,

void * msgp ,

size_t msgsz, ,

long msgtype , //那種型別的訊息

int  msgflg);

                      返回:

                           -1:失敗

                           大小:成功

               刪除佇列:msgctl 引數和shctl一樣

案例程式碼:

#include<unistd.h>

#include<sys/ipc.h>

#include<sys/msg.h>

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

struct  msgbuf

{

     long  type;

     char  data[32];

}

void main()

{

    key_t  key;

    int msgid;

    //1建立訊息佇列

     key= ftok(“ . ” , 254);

    if(key == -1) printf(“ftok error:%m\n”) , exit(-1);

    msgid= msgget(key,IPC_CREAT | IPC_EXCL|0666);

     if(msgid==-1) printf(“get error : %m\n”), exit(-1);

    //2構造訊息

     struct  msgbuf msg;

    //3傳送訊息

     for(i=1;i<=10;i++)

    {

          msg.type=1;        //訊息型別自己定義一個long型別

          sprintf(msg.data  , “Message:%d”,i);

          msgsnd(msgid ,&msg , strlen(msg.data) , 0);

    }

    //4刪除佇列

     //msgctl(msgid, IPC_RMID,0);

}

#include<unistd.h>

#include<sys/ipc.h>

#include<sys/msg.h>

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

struct  msgbuf

{

     long  type;

     char  data[32];

}

void main()

{

    key_t  key;

    int msgid;

    //1得到訊息佇列

    key = ftok(“ . ” , 254);

    if(key == -1) printf(“ftok error:%m\n”) , exit(-1);

    msgid= msgget(key,0);

    if(msgid== -1) printf(“get error : %m\n”), exit(-1);

    //2構造訊息

     struct  msgbuf msg;

    //3接收訊息

     while(1)

    {

         bzero(&msg,sizeof(msg));

         msgrcv(msgid , & msg sizeof(msg.data) , 1 , 0);

         printf(“%s\n”,msg.data);

    }

}

說明:如果訊息佇列中沒有訊息了讀取訊息的程式會阻塞等待

當程式傳送訊息到佇列中,一個程式讀取了所以訊息,佇列中就沒有訊息,就無法再讀取了,只能等待在傳送訊息後在讀取訊息。