涼了!張三同學沒答好「進程間通信」,被面試官掛了....
開場小故事


正文

管道
|」這個豎線。$?ps?auxf?|?grep?mysql
|」豎線就是一個管道,它的功能是將前一個命令(ps auxf)的輸出,作為后一個命令(grep mysql)的輸入,從這功能描述,可以看出管道傳輸數(shù)據(jù)是單向的,如果想相互通信,我們需要創(chuàng)建兩個管道才行。|」表示的管道稱為匿名管道,用完了就銷毀。FIFO,因為數(shù)據(jù)是先進先出的傳輸方式。mkfifo 命令來創(chuàng)建,并且指定管道名字:$?mkfifo?myPipe
$?ls?-l
prw-r--r--. 1?root????root?????????0?Jul?17?02:45?myPipe
$?echo?"hello"?>?myPipe??//?將數(shù)據(jù)寫進管道
?????????????????????????//?停住了?...
$?cat?hello
那管道如何創(chuàng)建呢,背后原理是什么?
int?pipe(int?fd[2])
fd[0],另一個是管道的寫入端描述符 fd[1]。注意,這個匿名管道是特殊的文件,只存在于內(nèi)存,不存于文件系統(tǒng)中。
fork 創(chuàng)建子進程,創(chuàng)建的子進程會復制父進程的文件描述符,這樣就做到了兩個進程各有兩個「 fd[0] 與 fd[1]」,兩個進程就可以通過各自的 fd 寫入和讀取同一個管道文件實現(xiàn)跨進程通信了。
父進程關閉讀取的 fd[0],只保留寫入的 fd[1]; 子進程關閉寫入的 fd[1],只保留讀取的 fd[0];

A | B命令的時候,A 進程和 B 進程都是 shell 創(chuàng)建出來的子進程,A 和 B 之間不存在父子關系,它倆的父進程都是 shell。
|」匿名管道將多個命令連接在一起,實際上也就是創(chuàng)建了多個子進程,那么在我們編寫 shell 腳本時,能使用一個管道搞定的事情,就不要多用一個管道,這樣可以減少創(chuàng)建子進程的系統(tǒng)開銷。消息隊列
MSGMAX 和 MSGMNB,它們以字節(jié)為單位,分別定義了一條消息的最大長度和一個隊列的最大長度。共享內(nèi)存

信號量
一個是 P 操作,這個操作會把信號量減去 -1,相減后如果信號量 < 0,則表明資源已被占用,進程需阻塞等待;相減后如果信號量 >= 0,則表明還有資源可使用,進程可正常繼續(xù)執(zhí)行。 另一個是 V 操作,這個操作會把信號量加上 1,相加后如果信號量 <= 0,則表明當前有阻塞中的進程,于是會將該進程喚醒運行;相加后如果信號量 > 0,則表明當前沒有阻塞中的進程;
1。
進程 A 在訪問共享內(nèi)存前,先執(zhí)行了 P 操作,由于信號量的初始值為 1,故在進程 A 執(zhí)行 P 操作后信號量變?yōu)?0,表示共享資源可用,于是進程 A 就可以訪問共享內(nèi)存。 若此時,進程 B 也想訪問共享內(nèi)存,執(zhí)行了 P 操作,結果信號量變?yōu)榱?-1,這就意味著臨界資源已被占用,因此進程 B 被阻塞。 直到進程 A 訪問完共享內(nèi)存,才會執(zhí)行 V 操作,使得信號量恢復為 0,接著就會喚醒阻塞中的線程 B,使得進程 B 可以訪問共享內(nèi)存,最后完成共享內(nèi)存的訪問后,執(zhí)行 V 操作,使信號量恢復到初始值 1。
1,就代表著是互斥信號量,它可以保證共享內(nèi)存在任何時刻只有一個進程在訪問,這就很好的保護了共享內(nèi)存。0。
如果進程 B 比進程 A 先執(zhí)行了,那么執(zhí)行到 P 操作時,由于信號量初始值為 0,故信號量會變?yōu)?-1,表示進程 A 還沒生產(chǎn)數(shù)據(jù),于是進程 B 就阻塞等待; 接著,當進程 A 生產(chǎn)完數(shù)據(jù)后,執(zhí)行了 V 操作,就會使得信號量變?yōu)?0,于是就會喚醒阻塞在 P 操作的進程 B; 最后,進程 B 被喚醒后,意味著進程 A 已經(jīng)生產(chǎn)了數(shù)據(jù),于是進程 B 就可以正常讀取數(shù)據(jù)了。
0,就代表著是同步信號量,它可以保證進程 A 應在進程 B 之前執(zhí)行。信號
kill -l 命令,查看所有的信號:$?kill?-l
?1)?SIGHUP???????2)?SIGINT???????3)?SIGQUIT??????4)?SIGILL???????5)?SIGTRAP
?6)?SIGABRT??????7)?SIGBUS???????8)?SIGFPE???????9)?SIGKILL?????10)?SIGUSR1
11)?SIGSEGV?????12)?SIGUSR2?????13)?SIGPIPE?????14)?SIGALRM?????15)?SIGTERM
16)?SIGSTKFLT???17)?SIGCHLD?????18)?SIGCONT?????19)?SIGSTOP?????20)?SIGTSTP
21)?SIGTTIN?????22)?SIGTTOU?????23)?SIGURG??????24)?SIGXCPU?????25)?SIGXFSZ
26)?SIGVTALRM???27)?SIGPROF?????28)?SIGWINCH????29)?SIGIO???????30)?SIGPWR
31)?SIGSYS??????34)?SIGRTMIN????35)?SIGRTMIN+1??36)?SIGRTMIN+2??37)?SIGRTMIN+3
38)?SIGRTMIN+4??39)?SIGRTMIN+5??40)?SIGRTMIN+6??41)?SIGRTMIN+7??42)?SIGRTMIN+8
43)?SIGRTMIN+9??44)?SIGRTMIN+10?45)?SIGRTMIN+11?46)?SIGRTMIN+12?47)?SIGRTMIN+13
48)?SIGRTMIN+14?49)?SIGRTMIN+15?50)?SIGRTMAX-14?51)?SIGRTMAX-13?52)?SIGRTMAX-12
53)?SIGRTMAX-11?54)?SIGRTMAX-10?55)?SIGRTMAX-9??56)?SIGRTMAX-8??57)?SIGRTMAX-7
58)?SIGRTMAX-6??59)?SIGRTMAX-5??60)?SIGRTMAX-4??61)?SIGRTMAX-3??62)?SIGRTMAX-2
63)?SIGRTMAX-1??64)?SIGRTMAX
Ctrl+C 產(chǎn)生 SIGINT信號,表示終止該進程;Ctrl+Z 產(chǎn)生 SIGTSTP信號,表示停止該進程,但還未結束;
kill 命令的方式給進程發(fā)送信號,但前提需要知道運行中的進程 PID 號,例如:kill -9 1050 ,表示給 PID 為 1050 的進程發(fā)送 SIGKILL信號,用來立即結束該進程;
SIGKILL 和 SEGSTOP,它們用于在任何時候中斷或結束某一進程。Socket
int?socket(int?domain,?int?type,?int?protocal)
domain 參數(shù)用來指定協(xié)議族,比如 AF_INET 用于 IPV4、AF_INET6 用于 IPV6、AF_LOCAL/AF_UNIX 用于本機; type 參數(shù)用來指定通信特性,比如 SOCK_STREAM 表示的是字節(jié)流,對應 TCP、SOCK_DGRAM ?表示的是數(shù)據(jù)報,對應 UDP、SOCK_RAW 表示的是原始套接字; protocal 參數(shù)原本是用來指定通信協(xié)議的,但現(xiàn)在基本廢棄。因為協(xié)議已經(jīng)通過前面兩個參數(shù)指定完成,protocol 目前一般寫成 0 即可;
實現(xiàn) TCP 字節(jié)流通信:socket 類型是 AF_INET 和 SOCK_STREAM; 實現(xiàn) UDP 數(shù)據(jù)報通信:socket 類型是 AF_INET 和 SOCK_DGRAM; 實現(xiàn)本地進程間通信:「本地字節(jié)流 socket 」類型是 AF_LOCAL 和 SOCK_STREAM,「本地數(shù)據(jù)報 socket 」類型是 AF_LOCAL 和 SOCK_DGRAM。另外,AF_UNIX 和 AF_LOCAL 是等價的,所以 AF_UNIX 也屬于本地 socket;
針對 TCP 協(xié)議通信的 socket 編程模型

服務端和客戶端初始化 socket,得到文件描述符;服務端調(diào)用 bind,將綁定在 IP 地址和端口;服務端調(diào)用 listen,進行監(jiān)聽;服務端調(diào)用 accept,等待客戶端連接;客戶端調(diào)用 connect,向服務器端的地址和端口發(fā)起連接請求;服務端 accept返回用于傳輸?shù)?socket的文件描述符;客戶端調(diào)用 write寫入數(shù)據(jù);服務端調(diào)用read讀取數(shù)據(jù);客戶端斷開連接時,會調(diào)用 close,那么服務端read讀取數(shù)據(jù)的時候,就會讀取到了EOF,待處理完數(shù)據(jù)后,服務端調(diào)用close,表示連接關閉。
accept 時,連接成功了會返回一個已完成連接的 socket,后續(xù)用來傳輸數(shù)據(jù)。針對 UDP 協(xié)議通信的 socket 編程模型

針對本地進程間通信的 socket 編程模型
本地 socket 的編程接口和 IPv4 、IPv6 套接字編程接口是一致的,可以支持「字節(jié)流」和「數(shù)據(jù)報」兩種協(xié)議; 本地 socket 的實現(xiàn)效率大大高于 IPv4 和 IPv6 的字節(jié)流、數(shù)據(jù)報 socket 實現(xiàn);
總結
|」豎線就是匿名管道,通信的數(shù)據(jù)是無格式的流并且大小受限,通信的方式是單向的,數(shù)據(jù)只能在一個方向上流動,如果要雙向通信,需要創(chuàng)建兩個管道,再來匿名管道是只能用于存在父子關系的進程間通信,匿名管道的生命周期隨著進程創(chuàng)建而建立,隨著進程終止而消失。SIGKILL 和 SEGSTOP,這是為了方便我們能在任何時候結束或停止某個進程。互斥的方式,可保證任意時刻只有一個線程訪問共享資源; 同步的方式,可保證線程 A 應在線程 B 之前執(zhí)行;

評論
圖片
表情
