Linux網路編程--處理序間通訊(一),linux網路編程

來源:互聯網
上載者:User

Linux網路編程--處理序間通訊(一),linux網路編程

處理序間通訊簡介(摘自《Linux網路編程》p85)

  AT&T 在 UNIX System V 中引入了幾種新的進程通訊方式,即訊息佇列( MessageQueues),訊號量( semaphores)和共用記憶體( shared memory),統稱為 System V IPC。在Linux 系統編程中,它們有著廣泛的應用。
  System V IPC 的一個顯著的特點,是它的具體執行個體在核心中是以對象的形式出現的,我們稱之為 IPC 對象。每個 IPC 對象在系統核心中都有一個唯一的標識符。通過標識符核心可以正確的引用指定的 IPC 對象.。需要注意的是,標識符的唯一性只在每一類的 IPC 對象內成立。比如說,一個訊息佇列和一個訊號量的標識符可能是相同的,但絕對不會出現兩個有相同標識符的訊息佇列。

  標識符只在核心中使用, IPC 對象在程式中是通過關鍵字( key)來訪問的。和 IPC 物件識別碼一樣,關鍵字也必須是唯一的。而且,要訪問同一個 IPC 對象, Server 和 Client必須使用同一個關鍵字。因此,如何構造新的關鍵字使之不和已有的關鍵字衝突,並保證Server 和 Client 使用的關鍵字是相同的,是建立 IPC 對象時首先要解決的一個問題。(具體在後邊的msg通訊中詳解)

通訊方法還有:半雙工管道pipe,具名管道fifo,訊息佇列,訊號量,共用內,socket通訊端等,下面一一介紹:

①半雙工管道:

  int pipe(int filedes[2]);

  管道是將兩個進程之間的標準輸入輸出相互對接的機制

  linux命令中使用的管道 |  : ls -l | grep *.c  //顯示檔案(輸入端)-(|)-(輸出端)>找到.c結尾檔案

實現:因為半雙工緣故,所以只能實現一段輸入,一段輸出,而不能雙向通訊。所以:實現為,通過管道串連進程,一端開放讀檔案描述,一端開放寫檔案描述

//管道的性質就是,一個進程的輸出作為另一個進程的輸入//那麼我們可以關閉一個進程讀端使之作為輸入端,//另一個進程關閉寫端,讀取資料,接收資料作為管道輸出端//FIFO具名管道//檔案系統中,具名管道是特殊檔案的方式存在的//不同進程可以通過具名管道共用資料//具名管道一直是阻塞方式的,且必須是顯示的通過open建立串連到管道的通道#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<sys/types.h>int main(){    int result = 1;    int fd[2];    pid_t pid;    int *write_fd = &fd[1];        //寫檔案描述    int *read_fd = &fd[0];        //讀檔案描述        int nbytes;    char str[] = "管道,你好\n";        char readBuffer[80];    memset(readBuffer,0,sizeof(readBuffer));    result = pipe(fd);        //建立管道    if(-1==result)    {        printf("管道建立失敗!\n");        return -1;    }        pid = fork();            //進程建立分叉程式    if(-1 == pid)    {        printf("fork失敗");        return -1;    }    if(0==pid)            //子進程關閉讀端,寫入字元    {        close(*read_fd);        result = write(*write_fd,str,strlen(str));        printf("寫入%d個資料\n",result);    }    else                //父進程關閉寫端,讀取資料    {        close(*write_fd);        nbytes = read(*read_fd,readBuffer,sizeof(readBuffer));        printf("接收到%d個資料,內容為%s",nbytes,readBuffer);    }    return 0;}

②具名管道

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

  類似於普通管道,只是

  a.在檔案系統中以裝置特殊檔案的形式存在

  b.不同進程之間可以通過具名管道共用資料

操作區別於普通管道:FIFO中必須顯式通過open建立串連到管道的通道,且總是處於阻塞狀態的

③訊息佇列

  訊息佇列是核心地址空間的內部鏈表,通過核心在各個進程之間傳遞內容。每個訊息佇列通過唯一IPC標識符標識,不同隊列相對獨立。

  

//file: msg.h
/* message buffer for msgsnd and msgrcv calls */struct msgbuf { __kernel_long_t mtype; /* type of message */ char mtext[1]; /* message text */};/* Obsolete, used only for backwards compatibility and libc5 compiles */struct msqid_ds { struct ipc_perm msg_perm; struct msg *msg_first; /* first message on queue,unused */ struct msg *msg_last; /* last message in queue,unused */ __kernel_time_t msg_stime; /* last msgsnd time */ __kernel_time_t msg_rtime; /* last msgrcv time */ __kernel_time_t msg_ctime; /* last change time */ unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */ unsigned long msg_lqbytes; /* ditto */ unsigned short msg_cbytes; /* current number of bytes on queue */ unsigned short msg_qnum; /* number of messages in queue */ unsigned short msg_qbytes; /* max number of bytes on queue */ __kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */ __kernel_ipc_pid_t msg_lrpid; /* last receive pid */};
//filename
/* Obsolete, used only for backwards compatibility and libc5 compiles */struct ipc_perm{ __kernel_key_t key;  //函數msgget()使用的索引值   __kernel_uid_t uid;  //使用者UID __kernel_gid_t gid;  //使用者GID __kernel_uid_t cuid;  //建立者UID __kernel_gid_t cgid;  //建立者GID __kernel_mode_t mode;   //許可權 unsigned short seq;  //序號};

  核心中的訊息佇列

註:結構list_head 形成一個鏈表,結構msg_msg之中的m_list使得訊息形成鏈表,尋找,插入時,對m_list域進行位移找到位置

相關函數:

  索引值構建 key_t ftok(const char* pathname,int proj_id);

  擷取訊息 int msgget(key_t key,int msgflg);

  發送訊息 int msgsnd(int msqid, const void * msgp,size_t msgsz,int msgflg);

  接收訊息 ssize_t msgrcv(int msqid, void * msgp, size_t msgsz, long msgtype, int msgflg);

  訊息控制 int msgctl(int msqid, int cmd, struct msqid_ds *buf);  //向核心發送cmd命令判斷進行何種操作

一個簡單例子

④訊號量

  訊號量是一種計數器,用來控制對多個進程共用的資源所進行的訪問。常用作鎖機制(生產者消費者模型是個典型使用)

  訊號量結構

//filename sys/sem.h
/* arg for semctl system calls. */union semun { int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */ unsigned short *array; /* 數組結構 */ struct seminfo *__buf; /* 訊號量內部結構 */ void *__pad;};

  相關函數 

  建立訊號量 int semget(key_t key, int nsems, int semflg);

  //key 來自於ftok()

  訊號量操作函數 int semop(int semid,struct sembuf* sops, unsigned nsops);

  //訊號量的P,V操作通過向已經建立好的訊號量發送命令完成

  控制訊號量參數

  int semctl(int semid, int semnum ,int cmd,.....);

  //用於在訊號量集合上執行控制操作

#include<stdio.h>#include<unistd.h>#include<sys/ipc.h>#include<sys/sem.h>#include<sys/types.h>typedef int sem_t;union semun{    int val;    struct semid_ds * buf;    unsigned short *array;}arg;sem_t CreateSem(key_t key, int value){    union semun sem;    sem_t semid;    sem.val = value;        semid = semget(key,0,IPC_CREAT);    if(-1 == semid)    {        printf("create semaphore error\n");        return -1;    }        semctl(semid,0,SETVAL,sem);        return semid;}int Sem_P(sem_t semid){struct sembuf sops = {0,+1,IPC_NOWAIT};return (semop(semid,&sops,1));}int Sem_V(sem_t semid){    struct sembuf sops = {0,-1,IPC_NOWAIT};    return (semop(semid,&sops,1));}void SetvalueSem(sem_t semid , int value){    union semun sem;    sem.val = value;    semctl(semid,0,SETVAL,sem);}int GetvalueSem(sem_t semid){    union semun sem;    return semctl(semid,0,GETVAL,sem);}void DestroySem(sem_t semid){    union semun sem;    sem.val = 0;    semctl(semid,0,IPC_RMID,sem);}int main(){    key_t key;    int semid;    char i;    int value = 0;    key = ftok("/ipc/sem",'a');        semid = CreateSem(key,100);    for( i = 0;i <= 3;++i)    {        Sem_P(semid);        Sem_V(semid);        }    value = GetvalueSem(semid);            DestroySem(semid);        return 0;}

⑤共用記憶體(最快捷的方法)沒有中間過程,管道等

  在多個進程之間共用記憶體地區的一種處理序間通訊方式,在多個進程之間對記憶體段進行映射的方式實現記憶體共用。

    相關函數

  建立共用記憶體函數 int shmget(key_y key, size_t size, int shmflg);

  獲得共用記憶體位址void * shmat(int shmid,const void* shmaddr, int shmflg);

  刪除共用記憶體函數 int shmdt(const void* shmadddr);

  共用記憶體控制函數 int shmctl(int shmid ,int cmd, struct shmid_ds * buf);

⑥訊號

  用於在一個或多個進程之間傳遞非同步訊號。

  相關函數

  訊號截取 sighandler signal(int signum ,sighandler handler);

  發送訊號 int kill(pid_t pid, int sig);

       int raise(int sig);

  

  

  

  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.