天天看點

Linux環境程式設計Day08-2

程序間通信

基本概念:

    什麼是程序間通信:

        是指兩個或多個程序之間互動資料的過程,是因為程序之間是互相獨立的,為了協同工作的需要必須要互動資料

    程序間通信的分類:

        簡單的程序間通信:信号、檔案、環境變量、指令行參數

        傳統的程序間通信:管道檔案

        XSI程序間通信:   共享記憶體、消息隊列、信号量

        網絡程序間通信:  套接字Socket

傳統程序間通信-管道(FIFO):

    管道是UNIX系統中最古老的程序間通信方式,古老意味着所有系統都支援,早期的管道檔案都是半雙工,現有的一些系統的管道是全雙工的

    管道是一種特殊的檔案,它的資料在檔案中是流動的,讀取之後就會消失,如果檔案中沒有任何資料讀取時會阻塞

    有名管道:基于有檔案名的管道檔案的通信

        程式設計模型:

            程序A                   程序B

            建立管道

            打開管道                打開管道

            寫資料                  讀資料

            關閉管道                關閉管道

            删除管道        

        建立管道檔案:

            1、mkfifo filename

            2、函數

            int mkfifo(const char *pathname, mode_t mode);  

            功能:建立有名管道檔案

            pathname:管道檔案路徑

            mode:管道檔案權限    

    匿名管道:

        注意:匿名管道隻适合通過fork建立的父子程序之間使用

        int pipe(int pipefd[2]);

        功能:建立一個匿名管道檔案,傳回管道檔案的讀權限fd和寫權限fd

        pipefd:傳回用于存儲管道檔案讀寫fd的數組,輸出型參數

                pipefd[0] 用于讀   

                pipefd[1] 用于寫

        程式設計模型:

            父程序                  子程序

        擷取一對fd                  共享了一對fd

        關閉讀                      關閉寫

        寫資料                      讀資料

        關閉寫                      關閉讀

XSI程序間通信:

    X/Open公司制定用于程序間通信的系統接口

    XSI程序間通信技術都需要借助系統核心,需要建立核心對象,核心對象會以整數形式傳回給使用者态,相當于檔案描述符,也叫做IPC辨別符

    檔案的建立打開需要借助檔案名,同樣的,IPC核心對象建立需要借助IPC鍵值(整數),必須要確定IPC鍵值是獨一無二的

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

    功能:計算出一個獨一無二的IPC鍵值

    pathname:項目路徑,不是依靠字元串計算,而是依靠路徑的位置以及項目編号計算的,是以不能提供假路徑,否則可能會産生同樣的IPC鍵值

    proj_id:項目編号

    傳回值:計算出來的IPC鍵值

共享記憶體:

    基本特點:

        兩個或者多個程序之間共享一塊由核心負責維護的記憶體,該記憶體可以與多個程序的虛拟記憶體進行映射

        優點:不需要複制資訊,是一種最快的IPC通信機制

        缺點:需要考慮同步通路的問題,一般借助信号來解決

        int shmget(key_t key, size_t size, int shmflg);

        功能:建立/擷取共享記憶體

        key:由程序提供的一個獨一無二的IPC鍵值

        size:共享記憶體的大小,擷取時該參數無意義,一般給0

        shmflg:

            IPC_CREAT   建立共享記憶體

            IPC_EXCL    共享記憶體如果已存在,則傳回錯誤

            擷取時直接給0

            mode_flags  建立共享記憶體時需要提供權限 IPC_CREAT|0644

        傳回值:IPC辨別符,錯誤時傳回-1

        void *shmat(int shmid, const void *shmaddr, int shmflg);

        功能:讓虛拟記憶體與共享記憶體進行映射

        shmid:IPC辨別符

        shmaddr:想要映射的虛拟記憶體首位址,為NULL時系統會自動操作

        shmflg:

            SHM_RDONLY:以隻讀方式映射共享記憶體

            SHM_RND:隻有當shmaddr參數不為NULL時有效,表示對shmaddr參數向下取記憶體頁的整數倍,作為映射位址

            如果都不需要,則寫0

        傳回值:與共享記憶體映射後的虛拟記憶體的首位址,失敗傳回(void *) -1 或者        0xFFFFFFFF

        int shmdt(const void *shmaddr);

        功能:取消映射

        shmaddr:映射過的虛拟記憶體首位址

        int shmctl(int shmid, int cmd, struct shmid_ds *buf);

        功能:删除/控制共享記憶體

        shmid:IPC辨別符

        cmd:

            IPC_STAT    擷取共享記憶體的屬性 則buf為輸出型參數

            IPC_SET     設定共享記憶體的屬性 則buf為輸入型參數

            IPC_RMID    删除共享記憶體       則buf給NULL

        buf:

         struct shmid_ds {

               struct ipc_perm shm_perm;    //所有者的相關資訊

               size_t          shm_segsz;   //共享記憶體的位元組數

               time_t          shm_atime;   //最後映射的時間

               time_t          shm_dtime;   //最後取消映射的時間

               time_t          shm_ctime;   //最後改變的時間

               pid_t           shm_cpid;    //建立者的程序号

               pid_t           shm_lpid;    //最後映射、取消映射者的程序号

               shmatt_t        shm_nattch;  //目前映射的次數

               ...

           };

        struct ipc_perm {

               key_t          __key;    //建立共享記憶體的IPC鍵值

               uid_t          uid;      //目前使用共享記憶體的使用者ID

               gid_t          gid;      //目前使用共享記憶體的組ID

               uid_t          cuid;     //建立共享記憶體的使用者ID

               gid_t          cgid;     //建立共享記憶體的使用者組ID

               unsigned short mode;     //共享記憶體的權限

               unsigned short __seq;    //共享記憶體的序列号

           };

    程式設計模型:

            程序A                   程序B

        建立共享記憶體            擷取共享記憶體

        映射共享記憶體            映射共享記憶體

        寫資料并通知其他程序     接收到通知後讀資料

        接收到通知後讀資料      寫資料并通知其他程序

        取消映射                取消映射

        删除共享記憶體            

消息隊列:

    基本特點:

        由核心維護管理的資料連結清單,是通過消息類型收發資料 

    int msgget(key_t key, int msgflg);

    功能:建立\擷取消息隊列

    key:IPC鍵值

    msgflg:

        IPC_CREAT   建立消息隊列

        IPC_EXCL    如果消息隊列已存在則傳回錯誤

        mode:       當建立消息隊列時需要提供權限

    傳回值:成功傳回IPC辨別符,失敗傳回-1

    int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

    功能:向消息隊列發送資料

    msqid:IPC辨別符

    msgp:要發送的消息的首位址

        struct msgbuf {

               long mtype;       // 消息類型

               char mtext[n];    // 資料

           };

    msgsz:資料的位元組數,是不包含消息類型的

    msgflg:

        阻塞一般寫0

        IPC_NOWAIT  當消息隊列滿時,不等待立即傳回

    ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);

    功能:從消息隊列中讀取資料

    msqid:IPC辨別符

    msgp:存儲資料結構體首位址

    msgsz:資料結構體的位元組數

    msgtyp:要讀取的消息類型,是按照類型的值來讀取消息,而不是按照順序

        >0 讀取消息隊列中第一條等于msgtyp的消息

        =0 讀取消息隊列中的第一條消息

        <0 讀取消息類型小于abs(msgtyp)的消息,如果有多個滿足則讀取值最小的

    msgflg:    

        IPC_NOWAIT 消息類型不符合時不阻塞,立即傳回

        MSG_EXCEPT 如果msgtyp>0,則讀取第一個消息類型不是msgtyp的消息

        MSG_NOERROR 如果不包含此标記,則消息的實際長度>msgsz,則會傳回錯誤,并且讀取失敗,如果包含此标記,則最多讀取msgsz個位元組,確定一定成功

    傳回值:成功讀取到的位元組數

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

    功能:删除/控制消息隊列

    msqid:IPC辨別符

    cmd:

        IPC_STAT    擷取消息隊列的屬性 則buf為輸出型參數

        IPC_SET     設定消息隊列的屬性 則buf為輸入型參數

        IPC_RMID    删除消息隊列       則buf給NULL

    buf:

    struct msqid_ds {

        struct ipc_perm msg_perm;     // 屬主資訊

        time_t          msg_stime;    // 最後發送時間

        time_t          msg_rtime;    // 最後接收時間

        time_t          msg_ctime;    // 最後修改時間

        unsigned long   __msg_cbytes; // 目前消息隊列位元組數

        msgqnum_t       msg_qnum;     // 目前的消息數量

        msglen_t        msg_qbytes;   // 消息的最大位元組數

        pid_t           msg_lspid;    // 最後發送者的PID

        pid_t           msg_lrpid;    // 最後接收者的PID

    };

    程式設計模型:

        程序A                       程序B

    建立消息隊列                    擷取消息隊列

    發送消息                        接收消息

    接收消息                        發送消息

    删除消息隊列

繼續閱讀