網(wǎng)絡(luò)通信信息安全】之深入解析進程之間的通信方式

      網(wǎng)友投稿 829 2022-05-29

      一、信號 Signal

      信號是 Linux 系統(tǒng)響應(yīng)某些條件而產(chǎn)生的一個事件,由操作系統(tǒng)事先定義,接收到該信號的進程可以采取自定義的行為,這是一種“訂閱-發(fā)布”的模式。

      信號來源分為硬件來源和軟件來源:

      硬件來源:如按下 CTRL+C、除 0、非法內(nèi)存訪問等;

      軟件來源:如 Kill 命令、Alarm Clock 超時,當(dāng) Reader 中止之后又向管道寫數(shù)據(jù)等。

      如下所示,Linux 系統(tǒng)上支持的 30 種不同類型的信號:

      一般的信號是都是由一個錯誤產(chǎn)生的。以除 0 為例,在 x86 機器上 DIV 或 IDIV 指令除數(shù)為 0 時,會引發(fā) 0 號中斷,編號 #DE(Divide Error),即所謂除零異常。這是一個硬件級中斷,會導(dǎo)致陷入內(nèi)核,執(zhí)行操作系統(tǒng)預(yù)定義在 IDT 中的中斷處理程序,而操作系統(tǒng)處理這個異常的方法,就是向進程發(fā)送一個信號 SIGFPE。如果進程設(shè)置相應(yīng)的 signal handler,就執(zhí)行進程的處理方法。否則,執(zhí)行操作系統(tǒng)的默認操作,一般這種信號的默認操作是殺死進程。

      同理,溢出、非法內(nèi)存訪問(越界)、非法指令等也都屬于硬件中斷,由操作系統(tǒng)處理。操作系統(tǒng)會將這些硬件異常包裝成“信號”發(fā)送給進程。如果進程不處理這幾個異常信號,那么默認的行為就是掛掉。

      但是,信號也可以作為進程間通信的一種方式,明確地由一個進程發(fā)送給另一個進程。

      進程如何發(fā)送信號?

      操作系統(tǒng)提供發(fā)送信號的系統(tǒng)調(diào)用;

      該系統(tǒng)調(diào)用會將信號放到目標(biāo)進程的信號隊列中;

      如果目標(biāo)進程未處于執(zhí)行狀態(tài),則該信號就由內(nèi)核保存起來,直到該進程恢復(fù)執(zhí)行并傳遞給它為止;

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

      進程如何接收信號?

      每個進程有一個信號隊列,放其它進程發(fā)給它、等待它處理的信號;

      進程在執(zhí)行過程中的特定時刻,檢查并處理自己的信號隊列,如從系統(tǒng)空間返回到用戶空間之前;

      發(fā)送信號時,必須指明發(fā)送目標(biāo)進程的號碼。一般用在具有親緣關(guān)系的進程之間。

      用戶進程對信號的處理過程有三種:

      處理信號:定義信號處理函數(shù),當(dāng)信號發(fā)生時,執(zhí)行相應(yīng)的處理函數(shù);

      忽略信號:當(dāng)不希望接收到的信號對進程的執(zhí)行產(chǎn)生影響,而讓進程繼續(xù)執(zhí)行時,可以忽略該信號,即不對信號進程作任何處理;

      不處理也不忽略:執(zhí)行默認操作,linux 對每種信號都規(guī)定了默認操作;

      有的信號,用戶進程是無法處理也無法忽略的,比如 SIGSTOP、SIGKILL 等。信號處理程序是一個用戶層函數(shù),進程可以為某個信號指定一個信號處理程序,接收到信號后,進程會跳轉(zhuǎn)執(zhí)行信號處理程序,執(zhí)行完成后再返回到中斷位置的下一條指令繼續(xù)執(zhí)行:

      二、管道 Pipe

      管道命令,在 Linux Shell 中經(jīng)常使用,一般使用管道操作符 | 來表示兩個命令之間的數(shù)據(jù)通信。比如:

      ps -ef | grep java | xargs echo

      1

      管道操作符的內(nèi)部實現(xiàn)其實就是 Linux 的管道接口,由管道操作符 | 分割的每個命令是獨立的進程,各個進程的標(biāo)準(zhǔn)輸出 STDOUT,會作為下一個進程的標(biāo)準(zhǔn)輸入 STDIN。

      ① 定義

      管道是一種半雙工的通信方式,數(shù)據(jù)只能單向流動,上游進程往管道中寫入數(shù)據(jù),下游進程從管道中接收數(shù)據(jù)。如果想實現(xiàn)雙方通信,那么需要建立兩個管道。

      管道適合于傳輸大量信息。管道發(fā)送的內(nèi)容是以字節(jié)為單位的,沒有格式的字節(jié)流。

      ② 創(chuàng)建管道

      通過 pipe() 系統(tǒng)調(diào)用來創(chuàng)建并打開一個管道,當(dāng)最后一個使用它的進程關(guān)閉對他的引用時,pipe 將自動撤銷。

      通過 pipe() 創(chuàng)建的是匿名管道,只能用于具有親緣關(guān)系的進程之間(父子進程或兄弟進程)。

      ③ 管道的實現(xiàn)

      管道就是一個文件,是一種只存在于內(nèi)存中的特殊的文件系統(tǒng)。

      在 Linux 中,管道借助文件系統(tǒng)的 File 結(jié)構(gòu)實現(xiàn),父進程使用 File 結(jié)構(gòu)保存向管道寫入數(shù)據(jù)的例程地址,子進程保存從管道讀出數(shù)據(jù)的例程地址,這解釋了上文所說的:

      單向流動;

      只能用于具有親緣關(guān)系的進程之間。

      管道是由內(nèi)核管理的一個緩沖區(qū),緩沖區(qū)被設(shè)計成為環(huán)形的數(shù)據(jù)結(jié)構(gòu),以便管道可以被循環(huán)利用(循環(huán)隊列)。

      ④ 管道的同步

      管道是一個具有特定大小的緩沖區(qū):

      操作系統(tǒng)會保證讀寫進程的同步;

      下游進程或者上游進程需要等另一方釋放鎖后才能操作管道,管道就相當(dāng)于一個文件,同一時刻只能有一個進程訪問;

      當(dāng)管道為空時,下游進程讀阻塞;當(dāng)管道滿時,上游進程寫阻塞;

      管道不再被任何進程使用時,自動消失。

      三、命名管道 FIFO

      Linux 管道包含匿名管道和命名管道,上文的匿名管道,只能用在親緣進程中,管道文件信息保存在內(nèi)存里。

      命名管道(FIFO)可用于沒有親緣的進程間,Pipe 和 FIFO 除了建立、打開、刪除的方式不同外,二者幾乎一模一樣。

      通過 mknode() 系統(tǒng)調(diào)用或者 mkfifo() 函數(shù)建立命名管道,一旦建立,任何有訪問權(quán)的進程都可以通過文件名將其打開和進行讀寫,而不局限于父子進程。

      建立命名管道時,會在磁盤中創(chuàng)建一個索引節(jié)點,命名管道的名字就相當(dāng)于索引節(jié)點的文件名。索引節(jié)點設(shè)置了進程的訪問權(quán)限,但是沒有數(shù)據(jù)塊。

      命名管道實質(zhì)上也是通過內(nèi)核緩沖區(qū)來實現(xiàn)數(shù)據(jù)傳輸,有訪問權(quán)限的進程,可以通過磁盤的索引節(jié)點來讀寫這塊緩沖區(qū)。

      當(dāng)不再被任何進程使用時,命名管道在內(nèi)存中釋放,但磁盤節(jié)點仍然存在。

      四、信號量 Semaphore

      信號量是一種特殊的變量,對它的操作都是原子的,有兩種操作:V(signal())和 P(wait())。

      V 操作會增加信號量 S 的數(shù)值,P 操作會減少它:

      V(S):如果有其他進程因等待 S 而被掛起,就讓它恢復(fù)運行,否則 S 加 1;

      P(S):如果 S 為 0,則掛起進程,否則 S 減 1;

      P、V 來自于荷蘭語:Probeer (try)、Verhoog (increment)。

      如果信號量是一個任意的整數(shù),通常被稱為計數(shù)信號量(Counting semaphore),或一般信號量(general semaphore);如果信號量只有二進制的 0 或 1,稱為二進制信號量(binary semaphore)。在 Linux 系統(tǒng)中,二進制信號量又稱互斥鎖(Mutex),信號量可以用于實現(xiàn)進程或線程的互斥和同步。

      信號量在底層的實現(xiàn)是通過硬件提供的原子指令,如 Test And Set、Compare And Swap 等。比如 golang 實現(xiàn)互斥量就是使用了 Compare And Swap 指令(go)。

      五、共享內(nèi)存 Shared Memory

      共享內(nèi)存顧名思義,允許兩個或多個進程共享同一段物理內(nèi)存,不同進程可以將同一段共享內(nèi)存映射到自己的地址空間,然后像訪問正常內(nèi)存一樣訪問它,不同進程可以通過向共享內(nèi)存端讀寫數(shù)據(jù)來交換信息。

      一個進程可以通過操作系統(tǒng)的系統(tǒng)調(diào)用,創(chuàng)建一塊共享內(nèi)存區(qū);其他進程通過系統(tǒng)調(diào)用把這段內(nèi)存映射到自己的用戶地址空間中;之后各個進程向讀寫正常內(nèi)存一樣,讀寫共享內(nèi)存。共享內(nèi)存區(qū)只會駐留在創(chuàng)建它的進程地址空間內(nèi)。

      共享內(nèi)存的優(yōu)點是簡單且高效,訪問共享內(nèi)存區(qū)域和訪問進程獨有的內(nèi)存區(qū)域一樣快,原因是不需要系統(tǒng)調(diào)用,不涉及用戶態(tài)到內(nèi)核態(tài)的轉(zhuǎn)換,也不需要對數(shù)據(jù)不必要的復(fù)制。

      比如管道和消息隊列,需要在內(nèi)核和用戶空間進行四次的數(shù)據(jù)拷貝(讀輸入文件、寫到管道;讀管道、寫到輸出文件),而共享內(nèi)存則只拷貝兩次:一次從輸入文件到共享內(nèi)存區(qū),另一次從共享內(nèi)存到輸出文件。

      此外,消息傳遞的實現(xiàn)經(jīng)常采用系統(tǒng)調(diào)用,也就經(jīng)常需要用戶態(tài)和內(nèi)核態(tài)互相轉(zhuǎn)換;而共享內(nèi)存只在建立共享內(nèi)存區(qū)域時需要系統(tǒng)調(diào)用;一旦建立共享內(nèi)存,所有訪問都可作為常規(guī)內(nèi)存訪問,無需借助內(nèi)核。

      共享內(nèi)存的缺點是存在并發(fā)問題,有可能出現(xiàn)多個進程修改同一塊內(nèi)存,因此共享內(nèi)存一般與信號量結(jié)合使用。

      Linux 的 2.2.x 內(nèi)核支持多種共享內(nèi)存方式,如 mmap() 系統(tǒng)調(diào)用,Posix 共享內(nèi)存,以及系統(tǒng) V 共享內(nèi)存;

      mmap() 系統(tǒng)調(diào)用的主要作用是將普通文件映射到進程的地址空間,然后可以像訪問普通內(nèi)存一樣對文件進行訪問,不必再調(diào)用 read(),write() 等操作;mmap() 不是專門用來共享內(nèi)存的,但是多個進程可以通過 mmap() 映射同一個普通文件,來實現(xiàn)共享內(nèi)存。

      系統(tǒng) V 則是通過映射特殊文件系統(tǒng) shm 中的文件實現(xiàn)進程間的共享內(nèi)存,通過 shmget 可以創(chuàng)建或獲得共享內(nèi)存的標(biāo)識符,取得共享內(nèi)存標(biāo)識符后,通過 shmat 將這個內(nèi)存區(qū)映射到本進程的虛擬地址空間。

      有關(guān) mmap() 系統(tǒng)調(diào)用、系統(tǒng) V 共享內(nèi)存的詳細介紹,以及兩者的對比,可以參考:

      Linux環(huán)境進程間通信 - 共享內(nèi)存(上);

      Linux環(huán)境進程間通信 - 共享內(nèi)存(下)。

      六、消息隊列 Message Queue

      消息隊列是一個消息的鏈表,保存在內(nèi)核中。消息隊列中的每個消息都是一個數(shù)據(jù)塊,具有特定的格式。操作系統(tǒng)中可以存在多個消息隊列,每個消息隊列有唯一的 key,稱為消息隊列標(biāo)識符。

      消息隊列克服了信號傳遞信息少、管道只能承載無格式字節(jié)流以及緩沖區(qū)大小受限等缺點。和信號相比,消息隊列能夠傳遞更多的信息。與管道相比,消息隊列提供了有格式的數(shù)據(jù),但消息隊列仍然有大小限制。

      消息隊列允許一個或多個進程向它寫入與讀取消息。消息的發(fā)送者和接收者不需要同時與消息隊列交互。消息會保存在隊列中,直到接收者取回它。也就是說,消息隊列是異步的,但這也造成了一個缺點,就是接收者必須輪詢消息隊列,才能收到最近的消息。

      操作系統(tǒng)提供創(chuàng)建消息隊列、取消息、發(fā)消息等系統(tǒng)調(diào)用。操作系統(tǒng)負責(zé)讀寫同步:若消息隊列已滿,則寫消息進程排隊等待;若取消息進程沒有找到需要的消息,則在等待隊列中尋找。

      消息隊列和管道相比,相同點在于二者都是通過發(fā)送-接收的方式進行通信,并且數(shù)據(jù)都有最大長度限制。不同點在于消息隊列的數(shù)據(jù)是有格式的,并且取消息進程可以選擇接收特定類型的消息,而不是像管道中那樣默認全部接收。

      【網(wǎng)絡(luò)通信與信息安全】之深入解析進程之間的通信方式

      七、套接字 Socket

      不同的計算機的進程之間通過 socket 通信,也可用于同一臺計算機的不同進程。

      需要通信的進程之間首先要各自創(chuàng)建一個 socket,內(nèi)容包括主機地址與端口號,聲明自己接收來自某端口地址的數(shù)據(jù)。

      進程通過 socket 把消息發(fā)送到網(wǎng)絡(luò)層中,網(wǎng)絡(luò)層通過主機地址將其發(fā)到目的主機,目的主機通過端口號發(fā)給對應(yīng)進程。

      操作系統(tǒng)提供創(chuàng)建 socket、發(fā)送、接收的系統(tǒng)調(diào)用,為每個 socket 設(shè)置發(fā)送緩沖區(qū)、接收緩沖區(qū)。

      八、總結(jié)

      任務(wù)調(diào)度 網(wǎng)絡(luò)

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:2021-09-30 網(wǎng)安實驗-Reverse-Ollydbg之?dāng)帱c設(shè)置
      下一篇:GaussDB Roach邏輯備份恢復(fù)
      相關(guān)文章
      一本天堂ⅴ无码亚洲道久久| 亚洲国产天堂久久综合| 亚洲图片在线观看| 亚洲第一页综合图片自拍| 亚洲国产精品99久久久久久| 亚洲精品成人网站在线播放| 亚洲精品视频在线| 亚洲性在线看高清h片| 亚洲AV无码专区在线观看成人| 亚洲精华国产精华精华液网站| 亚洲人成图片网站| 亚洲乱码在线播放| 中文字幕亚洲免费无线观看日本| 亚洲一区二区在线视频| 久久亚洲国产精品成人AV秋霞| 亚洲小视频在线观看| 亚洲影院在线观看| 亚洲美女视频一区| 亚洲人色大成年网站在线观看| 亚洲人成电影网站| 亚洲精品福利网泷泽萝拉| 亚洲综合色一区二区三区小说| 亚洲另类春色国产精品| 亚洲成a人片在线观看精品| 中文字幕亚洲精品无码| 亚洲av纯肉无码精品动漫| 亚洲AV永久无码精品一区二区国产| 亚洲国产精品成人一区| 亚洲最大av无码网址| 国产亚洲成av人片在线观看| 久久亚洲精品成人777大小说| 日本久久久久亚洲中字幕| 亚洲大片免费观看| 亚洲色大情网站www| 国产偷国产偷亚洲高清人| 中文字幕久久亚洲一区| 亚洲AV综合色区无码另类小说| 97久久精品亚洲中文字幕无码 | 中文字幕亚洲精品| 亚洲一级毛片免费在线观看| 亚洲一级毛片在线观|