進程間的通信方式

作者丨二營長的意大利炮手

鏈接: https://juejin.im/post/5d7efce9f265da03a049a921?

進程間的通信方式:

?? ?每個進程各自有不同的用戶地址空間玷犹,任何一個進程的全局變量在另一個進程中都看不到,所以進程之間要交換數(shù)據(jù)必須通過內(nèi)核,在內(nèi)核中開辟一塊緩沖區(qū)亭病,進程1把數(shù)據(jù)從用戶空間拷到內(nèi)核緩沖區(qū),進程2再從內(nèi)核緩沖區(qū)把數(shù)據(jù)讀走剿配,內(nèi)核提供的這種機制稱為進程間通信(IPC皂岔,InterProcess Communication)考抄。


1. 管道/匿名管道(pipe)


? ? ? ?管道是半雙工的渗勘,數(shù)據(jù)只能向一個方向流動沐绒;需要雙方通信時,需要建立起兩個管道旺坠。只能用于父子進程或者兄弟進程之間(具有親緣關(guān)系的進程);管道的實質(zhì)是一個內(nèi)核緩沖區(qū)乔遮,進程以先進先出的方式從緩沖區(qū)存取數(shù)據(jù),管道一端的進程順序的將數(shù)據(jù)寫入緩沖區(qū)取刃,另一端的進程則順序的讀出數(shù)據(jù)蹋肮。該緩沖區(qū)可以看做是一個循環(huán)隊列,讀和寫的位置都是自動增長的璧疗,不能隨意改變坯辩,一個數(shù)據(jù)只能被讀一次,讀出來以后在緩沖區(qū)就不復(fù)存在了崩侠。


2. 有名管道(FIFO)


管道類似與數(shù)據(jù)結(jié)構(gòu)中的隊列漆魔。有名管道不同于匿名管道之處在于它提供了一個路徑名與之關(guān)聯(lián),以有名管道的文件形式存在于文件系統(tǒng)中却音,這樣有送,即使與有名管道的創(chuàng)建進程不存在親緣關(guān)系的進程,只要可以訪問該路徑僧家,就能夠彼此通過有名管道相互通信雀摘,因此,通過有名管道不相關(guān)的進程也能交換數(shù)據(jù)八拱。值的注意的是阵赠,有名管道嚴(yán)格遵循先進先出(first in first out),對匿名管道及有名管道的讀總是從開始處返回數(shù)據(jù),對它們的寫則把數(shù)據(jù)添加到末尾肌稻。


?無名管道阻塞問題:無名管道無需顯示打開清蚀,創(chuàng)建時直接返回文件描述符,在讀寫時需要確定對方的存在爹谭,否則將退出枷邪。如果當(dāng)前進程向無名管道的一端寫數(shù)據(jù),必須確定另一端有某一進程诺凡。如果寫入無名管道的數(shù)據(jù)超過其最大值东揣,寫操作將阻塞,如果管道中沒有數(shù)據(jù)腹泌,讀操作將阻塞嘶卧,如果管道發(fā)現(xiàn)另一端斷開,將自動退出凉袱。

? ? ?有名管道阻塞問題:有名管道在打開時需要確實對方的存在芥吟,否則將阻塞侦铜。即以讀方式打開某管道,在此之前必須一個進程以寫方式打開管道钟鸵,否則阻塞钉稍。此外,可以以讀寫(O_RDWR)模式打開有名管道棺耍,即當(dāng)前進程讀贡未,當(dāng)前進程寫,不會阻塞烈掠。


3. 信號(Signal)


信號是Linux系統(tǒng)中用于進程間互相通信或者操作的一種機制羞秤,信號可以在任何時候發(fā)給某一進程缸托,而無需知道該進程的狀態(tài)左敌。

如果該進程當(dāng)前并未處于執(zhí)行狀態(tài),則該信號就有內(nèi)核保存起來俐镐,知道該進程回復(fù)執(zhí)行并傳遞給它為止矫限。

如果一個信號被進程設(shè)置為阻塞,則該信號的傳遞被延遲佩抹,直到其阻塞被取消是才被傳遞給進程叼风。


Linux系統(tǒng)中常用信號:

(1)SIGHUP:用戶從終端注銷,所有已啟動進程都將收到該進程棍苹。系統(tǒng)缺省狀態(tài)下對該信號的處理是終止進程无宿。

(2)SIGINT:程序終止信號。程序運行過程中枢里,按Ctrl+C鍵將產(chǎn)生該信號孽鸡。

(3)SIGQUIT:程序退出信號。程序運行過程中栏豺,按Ctrl+鍵將產(chǎn)生該信號彬碱。

(4)SIGBUS和SIGSEGV:進程訪問非法地址。

(5)SIGFPE:運算中出現(xiàn)致命錯誤奥洼,如除零操作巷疼、數(shù)據(jù)溢出等。

(6)SIGKILL:用戶終止進程執(zhí)行信號灵奖。shell下執(zhí)行kill -9發(fā)送該信號嚼沿。

(7)SIGTERM:結(jié)束進程信號。shell下執(zhí)行kill 進程pid發(fā)送該信號瓷患。

(8)SIGALRM:定時器信號伏尼。

(9)SIGCLD:子進程退出信號。如果其父進程沒有忽略該信號也沒有處理該信號尉尾,則子進程退出后將形成僵尸進程爆阶。


信號來源

信號是軟件層次上對中斷機制的一種模擬,是一種異步通信方式,辨图,信號可以在用戶空間進程和內(nèi)核之間直接交互班套,內(nèi)核可以利用信號來通知用戶空間的進程發(fā)生了哪些系統(tǒng)事件,信號事件主要有兩個來源:

硬件來源:用戶按鍵輸入Ctrl+C退出故河、硬件異常如無效的存儲訪問等吱韭。

軟件終止:終止進程信號、其他進程調(diào)用kill函數(shù)鱼的、軟件異常產(chǎn)生信號理盆。


信號生命周期和處理流程

(1)信號被某個進程產(chǎn)生,并設(shè)置此信號傳遞的對象(一般為對應(yīng)進程的pid)凑阶,然后傳遞給操作系統(tǒng)猿规;

(2)操作系統(tǒng)根據(jù)接收進程的設(shè)置(是否阻塞)而選擇性的發(fā)送給接收者,如果接收者阻塞該信號(且該信號是可以阻塞的)宙橱,操作系統(tǒng)將暫時保留該信號姨俩,而不傳遞,直到該進程解除了對此信號的阻塞(如果對應(yīng)進程已經(jīng)退出师郑,則丟棄此信號)环葵,如果對應(yīng)進程沒有阻塞,操作系統(tǒng)將傳遞此信號宝冕。

(3)目的進程接收到此信號后张遭,將根據(jù)當(dāng)前進程對此信號設(shè)置的預(yù)處理方式,暫時終止當(dāng)前代碼的執(zhí)行地梨,保護上下文(主要包括臨時寄存器數(shù)據(jù)菊卷,當(dāng)前程序位置以及當(dāng)前CPU的狀態(tài))、轉(zhuǎn)而執(zhí)行中斷服務(wù)程序湿刽,執(zhí)行完成后在回復(fù)到中斷的位置的烁。當(dāng)然,對于搶占式內(nèi)核诈闺,在中斷返回時還將引發(fā)新的調(diào)度渴庆。


4. 消息(Message)隊列


消息隊列是存放在內(nèi)核中的消息鏈表,每個消息隊列由消息隊列標(biāo)識符表示雅镊。

與管道(無名管道:只存在于內(nèi)存中的文件襟雷;命名管道:存在于實際的磁盤介質(zhì)或者文件系統(tǒng))不同的是消息隊列存放在內(nèi)核中,只有在內(nèi)核重啟(即仁烹,操作系統(tǒng)重啟)或者顯示地刪除一個消息隊列時耸弄,該消息隊列才會被真正的刪除。

另外與管道不同的是卓缰,消息隊列在某個進程往一個隊列寫入消息之前计呈,并不需要另外某個進程在該隊列上等待消息的到達砰诵。延伸閱讀:消息隊列C語言的實踐


消息隊列特點總結(jié):
(1)消息隊列是消息的鏈表,具有特定的格式,存放在內(nèi)存中并由消息隊列標(biāo)識符標(biāo)識.

(2)消息隊列允許一個或多個進程向它寫入與讀取消息.

(3)管道和消息隊列的通信數(shù)據(jù)都是先進先出的原則。

(4)消息隊列可以實現(xiàn)消息的隨機查詢,消息不一定要以先進先出的次序讀取,也可以按消息的類型讀取.比FIFO更有優(yōu)勢捌显。

(5)消息隊列克服了信號承載信息量少茁彭,管道只能承載無格式字 節(jié)流以及緩沖區(qū)大小受限等缺。

(6)目前主要有兩種類型的消息隊列:POSIX消息隊列以及System V消息隊列扶歪,系統(tǒng)V消息隊列目前被大量使用理肺。系統(tǒng)V消息隊列是隨內(nèi)核持續(xù)的,只有在內(nèi)核重起或者人工刪除時善镰,該消息隊列才會被刪除妹萨。


5. 共享內(nèi)存(share memory)

使得多個進程可以可以直接讀寫同一塊內(nèi)存空間,是最快的可用IPC形式炫欺。是針對其他通信機制運行效率較低而設(shè)計的乎完。

為了在多個進程間交換信息,內(nèi)核專門留出了一塊內(nèi)存區(qū)竣稽,可以由需要訪問的進程將其映射到自己的私有地址空間囱怕。進程就可以直接讀寫這一塊內(nèi)存而不需要進行數(shù)據(jù)的拷貝霍弹,從而大大提高效率毫别。

由于多個進程共享一段內(nèi)存,因此需要依靠某種同步機制(如信號量)來達到進程間的同步及互斥典格。

延伸閱讀:Linux支持的主要三種共享內(nèi)存方式:mmap()系統(tǒng)調(diào)用岛宦、Posix共享內(nèi)存,以及System V共享內(nèi)存實踐

6. 信號量(semaphore)


信號量是一個計數(shù)器耍缴,用于多進程對共享數(shù)據(jù)的訪問砾肺,信號量的意圖在于進程間同步。

為了獲得共享資源防嗡,進程需要執(zhí)行下列操作:

(1)創(chuàng)建一個信號量:這要求調(diào)用者指定初始值变汪,對于二值信號量來說,它通常是1蚁趁,也可是0裙盾。

(2)等待一個信號量:該操作會測試這個信號量的值,如果小于0他嫡,就阻塞番官。也稱為P操作。

(3)掛出一個信號量:該操作將信號量的值加1钢属,也稱為V操作徘熔。


為了正確地實現(xiàn)信號量,信號量值的測試及減1操作應(yīng)當(dāng)是原子操作淆党。為此酷师,信號量通常是在內(nèi)核中實現(xiàn)的讶凉。Linux環(huán)境中,有三種類型:Posix(可移植性操作系統(tǒng)接口)有名信號量(使用Posix IPC名字標(biāo)識)山孔、Posix基于內(nèi)存的信號量(存放在共享內(nèi)存區(qū)中)缀遍、System V信號量(在內(nèi)核中維護)。這三種信號量都可用于進程間或線程間的同步饱须。

兩個進程使用一個二值信號量


兩個進程所以用一個Posix有名二值信號量

信號量與普通整型變量的區(qū)別:

(1)信號量是非負(fù)整型變量域醇,除了初始化之外,它只能通過兩個標(biāo)準(zhǔn)原子操作:wait(semap) , signal(semap) ; 來進行訪問蓉媳;

(2)操作也被成為PV原語(P來源于荷蘭語proberen"測試"譬挚,V來源于荷蘭語verhogen"增加",P表示通過的意思酪呻,V表示釋放的意思)减宣,而普通整型變量則可以在任何語句塊中被訪問;


信號量與互斥量之間的區(qū)別:

(1)互斥量用于線程的互斥玩荠,信號量用于線程的同步漆腌。這是互斥量和信號量的根本區(qū)別,也就是互斥和同步之間的區(qū)別阶冈。

互斥:是指某一資源同時只允許一個訪問者對其進行訪問闷尿,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序女坑,即訪問是無序的填具。

同步:是指在互斥的基礎(chǔ)上(大多數(shù)情況),通過其它機制實現(xiàn)訪問者對資源的有序訪問匆骗。

在大多數(shù)情況下劳景,同步已經(jīng)實現(xiàn)了互斥,特別是所有寫入資源的情況必定是互斥的碉就。少數(shù)情況是指可以允許多個訪問者同時訪問資源

(2)互斥量值只能為0/1盟广,信號量值可以為非負(fù)整數(shù)。

也就是說瓮钥,一個互斥量只能用于一個資源的互斥訪問筋量,它不能實現(xiàn)多個資源的多線程互斥問題。信號量可以實現(xiàn)多個同類資源的多線程互斥和同步骏庸。當(dāng)信號量為單值信號量是毛甲,也可以完成一個資源的互斥訪問。

(3)互斥量的加鎖和解鎖必須由同一線程分別對應(yīng)使用具被,信號量可以由一個線程釋放玻募,另一個線程得到。


7. 套接字(socket)


套接字是一種通信機制一姿,憑借這種機制七咧,客戶/服務(wù)器(即要進行通信的進程)系統(tǒng)的開發(fā)工作既可以在本地單機上進行跃惫,也可以跨網(wǎng)絡(luò)進行。也就是說它可以讓不在同一臺計算機但通過網(wǎng)絡(luò)連接計算機上的進程進行通信艾栋。

Socket是應(yīng)用層和傳輸層之間的橋梁爆存。

套接字是支持TCP/IP的網(wǎng)絡(luò)通信的基本操作單元,可以看做是不同主機之間的進程進行雙向通信的端點蝗砾,簡單的說就是通信的兩方的一種約定先较,用套接字中的相關(guān)函數(shù)來完成通信過程。

套接字特性

套接字的特性由3個屬性確定悼粮,它們分別是:域闲勺、端口號、協(xié)議類型扣猫。

(1)套接字的域

它指定套接字通信中使用的網(wǎng)絡(luò)介質(zhì)菜循,最常見的套接字域有兩種:

一是AF_INET,它指的是Internet網(wǎng)絡(luò)申尤。當(dāng)客戶使用套接字進行跨網(wǎng)絡(luò)的連接時癌幕,它就需要用到服務(wù)器計算機的IP地址和端口來指定一臺聯(lián)網(wǎng)機器上的某個特定服務(wù),所以在使用socket作為通信的終點昧穿,服務(wù)器應(yīng)用程序必須在開始通信之前綁定一個端口勺远,服務(wù)器在指定的端口等待客戶的連接。

另一個域AF_UNIX粤咪,表示UNIX文件系統(tǒng)谚中,它就是文件輸入/輸出渴杆,而它的地址就是文件名寥枝。

(2)套接字的端口號

每一個基于TCP/IP網(wǎng)絡(luò)通訊的程序(進程)都被賦予了唯一的端口和端口號,端口是一個信息緩沖區(qū)磁奖,用于保留Socket中的輸入/輸出信息茸塞,端口號是一個16位無符號整數(shù)丰捷,范圍是0-65535,以區(qū)別主機上的每一個程序(端口號就像房屋中的房間號),低于256的端口號保留給標(biāo)準(zhǔn)應(yīng)用程序弧满,比如pop3的端口號就是110,每一個套接字都組合進了IP地址锭环、端口禾酱,這樣形成的整體就可以區(qū)別每一個套接字。

(3)套接字協(xié)議類型

因特網(wǎng)提供三種通信機制霉赡,一是流套接字橄务,流套接字在域中通過TCP/IP連接實現(xiàn),同時也是AF_UNIX中常用的套接字類型穴亏。流套接字提供的是一個有序蜂挪、可靠重挑、雙向字節(jié)流的連接,因此發(fā)送的數(shù)據(jù)可以確保不會丟失棠涮、重復(fù)或亂序到達谬哀,而且它還有一定的出錯后重新發(fā)送的機制。

二個是數(shù)據(jù)報套接字严肪,它不需要建立連接和維持一個連接史煎,它們在域中通常是通過UDP/IP協(xié)議實現(xiàn)的。它對可以發(fā)送的數(shù)據(jù)的長度有限制驳糯,數(shù)據(jù)報作為一個單獨的網(wǎng)絡(luò)消息被傳輸,它可能會丟失劲室、復(fù)制或錯亂到達,UDP不是一個可靠的協(xié)議结窘,但是它的速度比較高很洋,因為它并一需要總是要建立和維持一個連接。

三是原始套接字隧枫,原始套接字允許對較低層次的協(xié)議直接訪問喉磁,比如IP、 ICMP協(xié)議官脓,它常用于檢驗新的協(xié)議實現(xiàn)协怒,或者訪問現(xiàn)有服務(wù)中配置的新設(shè)備,因為RAW SOCKET可以自如地控制Windows下的多種協(xié)議卑笨,能夠?qū)W(wǎng)絡(luò)底層的傳輸機制進行控制孕暇,所以可以應(yīng)用原始套接字來操縱網(wǎng)絡(luò)層和傳輸層應(yīng)用。比如赤兴,我們可以通過RAW SOCKET來接收發(fā)向本機的ICMP妖滔、IGMP協(xié)議包,或者接收TCP/IP棧不能夠處理的IP包桶良,也可以用來發(fā)送一些自定包頭或自定協(xié)議的IP包座舍。網(wǎng)絡(luò)監(jiān)聽技術(shù)很大程度上依賴于SOCKET_RAW。

原始套接字與標(biāo)準(zhǔn)套接字的區(qū)別在于:原始套接字可以讀寫內(nèi)核沒有處理的IP數(shù)據(jù)包陨帆,而流套接字只能讀取TCP協(xié)議的數(shù)據(jù)曲秉,數(shù)據(jù)報套接字只能讀取UDP協(xié)議的數(shù)據(jù)。因此疲牵,如果要訪問其他協(xié)議發(fā)送數(shù)據(jù)必須使用原始套接字承二。

服務(wù)器端

(1)首先服務(wù)器應(yīng)用程序用系統(tǒng)調(diào)用socket來創(chuàng)建一個套接字,它是系統(tǒng)分配給該服務(wù)器進程的類似文件描述符的資源纲爸,它不能與其他的進程共享亥鸠。

(2)然后,服務(wù)器進程會給套接字起個名字缩焦,我們使用系統(tǒng)調(diào)用bind來給套接字命名读虏。然后服務(wù)器進程就開始等待客戶連接到這個套接字责静。

(3)接下來,系統(tǒng)調(diào)用listen來創(chuàng)建一個隊列并將其用于存放來自客戶的進入連接盖桥。

(4)最后灾螃,服務(wù)器通過系統(tǒng)調(diào)用accept來接受客戶的連接。它會創(chuàng)建一個與原有的命名套接不同的新套接字揩徊,這個套接字只用于與這個特定客戶端進行通信腰鬼,而命名套接字(即原先的套接字)則被保留下來繼續(xù)處理來自其他客戶的連接(建立客戶端和服務(wù)端的用于通信的流,進行通信)塑荒。

客戶端

(1)客戶應(yīng)用程序首先調(diào)用socket來創(chuàng)建一個未命名的套接字熄赡,然后將服務(wù)器的命名套接字作為一個地址來調(diào)用connect與服務(wù)器建立連接。

(2)一旦連接建立齿税,我們就可以像使用底層的文件描述符那樣用套接字來實現(xiàn)雙向數(shù)據(jù)的通信(通過流進行數(shù)據(jù)傳輸)彼硫。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市凌箕,隨后出現(xiàn)的幾起案子拧篮,更是在濱河造成了極大的恐慌,老刑警劉巖牵舱,帶你破解...
    沈念sama閱讀 212,080評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件串绩,死亡現(xiàn)場離奇詭異,居然都是意外死亡芜壁,警方通過查閱死者的電腦和手機礁凡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來慧妄,“玉大人顷牌,你說我怎么就攤上這事⊙В” “怎么了韧掩?”我有些...
    開封第一講書人閱讀 157,630評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長窖铡。 經(jīng)常有香客問我,道長坊谁,這世上最難降的妖魔是什么费彼? 我笑而不...
    開封第一講書人閱讀 56,554評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮口芍,結(jié)果婚禮上箍铲,老公的妹妹穿的比我還像新娘。我一直安慰自己鬓椭,他們只是感情好颠猴,可當(dāng)我...
    茶點故事閱讀 65,662評論 6 386
  • 文/花漫 我一把揭開白布关划。 她就那樣靜靜地躺著,像睡著了一般翘瓮。 火紅的嫁衣襯著肌膚如雪贮折。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,856評論 1 290
  • 那天资盅,我揣著相機與錄音调榄,去河邊找鬼。 笑死呵扛,一個胖子當(dāng)著我的面吹牛每庆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播今穿,決...
    沈念sama閱讀 39,014評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼缤灵,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蓝晒?” 一聲冷哼從身側(cè)響起凤价,我...
    開封第一講書人閱讀 37,752評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎拔创,沒想到半個月后利诺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,212評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡剩燥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,541評論 2 327
  • 正文 我和宋清朗相戀三年慢逾,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片灭红。...
    茶點故事閱讀 38,687評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡侣滩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出变擒,到底是詐尸還是另有隱情君珠,我是刑警寧澤,帶...
    沈念sama閱讀 34,347評論 4 331
  • 正文 年R本政府宣布娇斑,位于F島的核電站策添,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏毫缆。R本人自食惡果不足惜唯竹,卻給世界環(huán)境...
    茶點故事閱讀 39,973評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望苦丁。 院中可真熱鬧浸颓,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至晋涣,卻和暖如春仪媒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背姻僧。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評論 1 266
  • 我被黑心中介騙來泰國打工规丽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人撇贺。 一個月前我還...
    沈念sama閱讀 46,406評論 2 360
  • 正文 我出身青樓赌莺,卻偏偏與公主長得像,于是被迫代替她去往敵國和親松嘶。 傳聞我的和親對象是個殘疾皇子艘狭,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,576評論 2 349