Linux 常见的六大 IPC 通信方式
Linux環境下,進程地址空間相互獨立,每個進程各自有不同的用戶地址空間。任何一個進程的全局變量在另一個進程中都看不到,所以進程和進程之間不能相互訪問,要交換數據必須通過內核,在內核中開辟一塊緩沖區,進程1把數據從用戶空間拷到內核緩沖區,進程2再從內核緩沖區把數據讀走,內核提供的這種機制稱為進程間通信(IPC,InterProcessCommunication)。今天我們來看一下,Linux下常見的六大IPC通信方式。
1、信號
信號是Unix/Linux系統在一定條件下生成的事件。信號是一種異步通信機制,進程不需要執行任何操作來等待信號的到達。信號異步通知接收信號的進程發生了某個事件,然后操作系統將會中斷接收到信號的進程的執行,轉而去執行相應的信號處理程序。
- (1)注冊信號處理函數
- (2)發送信號
- (3)信號集 信號集被定義為:
2、管道(Pipe)
管道用來連接不同進程之間的數據流。
- (1)在兩個程序之間傳遞數據的最簡單的方法是使用popen()和pclose()函數:
popen()函數首先調用一個shell,然后把command作為參數傳遞給shell。這樣每次調用popen()函數都需要啟動兩個進程;但是由于在Linux中,所有的參數擴展(parameter expansion)都是由shell執行的,這樣command中包含的所有參數擴展都可以在command程序啟動之前完成。
- (2)pipe()函數:
popen()函數只能返回一個管道描述符,并且返回的是文件流(filestream),可以使用函數fread()和fwrite()來訪問。pipe()函數可以返回兩個管道描述符:pipefd[0]和pipefd[1],任何寫入pipefd[1]的數據都可以從pipefd[0]讀回;pipe()函數返回的是文件描述符(file descriptor),因此只能使用底層的read()和write()系統調用來訪問。pipe()函數通常用來實現父子進程之間的通信。
- (3)命名管道:FIFO
前面兩種管道只能用在相關的程序之間,使用命名管道可以解決這個問題。在使用open()打開FIFO時,mode中不能包含O_RDWR。mode最常用的是O_RDONLY,O_WRONLY與O_NONBLOCK的組合。O_NONBLOCK影響了read()和write()在FIFO上的執行方式。
3、信號量(Semaphores)
System V的信號量集表示的是一個或多個信號量的集合。內核為每個信號量集維護一個semid_ds數據結構,而信號量集中的每個信號量使用一個無名結構體表示,這個結構體至少包含以下成員:
struct{unsigned short semval;//信號量值,總是>=0pid_t sempid; //上一次操作的pid…}; 復制代碼- (1)創建或訪問信號量
nsems指定信號量集中信號量的個數,如果只是獲取信號量集的標識符(而非新建),那么nsems可以為0。flag的低9位作為信號量的訪問權限位,類似于文件的訪問權限;如果flag中同時指定了IPC_CREAT和IPC_EXCL,那么如果key已與現存IPC對象想關聯的話,函數將會返回EEXIST錯誤。例如,flag可以為IPC_CREAT|0666。
- (2)控制信號量集
對semid信號量集合執行cmd操作;cmd常用的兩個值是:SETVAL初始化第semnum個信號量的值為arg.val;IPC_RMID刪除信號量。
- (3)對一個或多個信號量進行操作
4、共享內存
共享內存允許兩個或多個進程共享一定的存儲區,因為不需要拷貝數據,所以這是最快的一種IPC。
- (1)創建或訪問共享內存
- (2)附加共享內存到進程的地址空間
- (3)從進程的地址空間分離共享內存
- (4)控制共享內存
cmd的常用取值有:
(a)IPC_STAT獲取當前共享內存的shmid_ds結構并保存在buf中
(b)IPC_SET使用buf中的值設置當前共享內存的shmid_ds結構
(c)IPC_RMID刪除當前共享內存
5、消息隊列
消息隊列保存在內核中,是一個由消息組成的鏈表。
- (1)創建或訪問消息隊列
- (2)操作消息隊列
msg指向的結構體必須以一個longint成員開頭,作為msgrcv()的消息類型,必須大于0。nbytes指的是msg指向結構體的大小,但不包括longint部分的大小 ssize_t msgrcv(intmsqid,void *msg,size_t nbytes,long msgtype,int msgflg); 如果msgtype是0,就返回消息隊列中的第一個消息;如果是正整數,就返回隊列中的第一個該類型的消息;如果是負數,就返回隊列中具有最小值的第一個消息,并且該最小值要小于等于msgtype的絕對值。
- (3)控制消息隊列
6、Socket
套接字(Socket)是由Berkeley在BSD系統中引入的一種基于連接的IPC,是對網絡接口(硬件)和網絡協議(軟件)的抽象。它既解決了無名管道只能在相關進程間單向通信的問題,又解決了網絡上不同主機之間無法通信的問題。
??套接字有三個屬性:域(domain)、類型(type)和協議(protocol),對應于不同的域,套接字還有一個地址(address)來作為它的名字。
??域(domain)指定了套接字通信所用到的協議族,最常用的域是AF_INET,代表網絡套接字,底層協議是IP協議。對于網絡套接字,由于服務器端有可能會提供多種服務,客戶端需要使用IP端口號來指定特定的服務。AF_UNIX代表本地套接字,使用Unix/Linux文件系統實現。
??IP協議提供了兩種通信手段:流(streams)和數據報(datagrams),對應的套接字類型(type)分別為流式套接字和數據報套接字。流式套接字(SOCK_STREAM)用于提供面向連接、可靠的數據傳輸服務。該服務保證數據能夠實現無差錯、無重復發送,并按順序接收。流式套接字使用TCP協議。數據報套接字(SOCK_DGRAM)提供了一種無連接的服務。該服務并不能保證數據傳輸的可靠性,數據有可能在傳輸過程中丟失或出現數據重復,且無法保證順序地接收到數據。數據報套接字使用UDP協議。
??一種類型的套接字可能可以使用多于一種的協議來實現,套接字的協議(protocol)屬性用于指定一種特定的協議。 ??
- (1)創建套接字
對于SOCK_STREAM和SOCK_DGRAM而言,分別只有一種協議支持這種類型的套接字。因此protocol可以為0,表示默認的協議。
- (2) 綁定套接字
- (3)監聽套接字
- (4)等待接受連接
當客戶端程序嘗試連接sockfd套接字時,accept返回一個新的套接字與客戶端進行通信。如果addr不是NULL,那么客戶端的地址將會保存在addr所指向的結構體中;調用accept()前必須先將addrlen初始化為addr所指向結構體的大小,accept()返回以后,addrlen將會被設置成客戶端套接字地址結構體的實際大小。然后,通過對accept()返回的套接字執行read()和write()操作即可實現與客戶端的簡單的通信。 ??
- (5)建立連接(客戶端)
connect()在無名套接字sockfd和addr之間建立連接。addr指向的結構體中可以包含服務器的IP地址和端口號等信息。
- (6)數據傳輸
- (7)關閉套接字
- (8)主機字節序和網絡字節序的轉換
總結
以上是生活随笔為你收集整理的Linux 常见的六大 IPC 通信方式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows Vista for De
- 下一篇: linux 其他常用命令