关于进程间通信的学习心得
進(jìn)程:進(jìn)程是指獨(dú)立地址空間的指令序列
進(jìn)程的五種狀態(tài):新建,就緒,運(yùn)行,睡眠,僵死
進(jìn)程間通信:是不同進(jìn)程之間進(jìn)行一些"接觸",這種接觸有簡(jiǎn)單,有復(fù)雜。機(jī)制不同,復(fù)雜度也不同。通信是一個(gè)廣義上的意義,不僅指大批量數(shù)據(jù)傳送,還包括控制信息的傳送,但使用方法是基本相同的。
基本的進(jìn)程通信機(jī)制
1.傳統(tǒng)UNIX-IPC機(jī)制:信號(hào)和管道
2.SystemV的IPC機(jī)制:共享內(nèi)存、信號(hào)量和消息隊(duì)列
3.起源于Unix BSD版本的套結(jié)字(Socket)
4.遠(yuǎn)程過(guò)程調(diào)用(RPC)
信號(hào):Unix系統(tǒng)中使用的最古老的進(jìn)程間通訊的方法之一,用于向一個(gè)或多個(gè)進(jìn)程發(fā)送異步事件的信號(hào)。信號(hào)可以類(lèi)比于DOS下的INT或者是Windows下的事件。在有一個(gè)信號(hào)發(fā)生的時(shí)候,相應(yīng)的信號(hào)就會(huì)發(fā)送給相應(yīng)的進(jìn)程。
信號(hào)機(jī)制的實(shí)現(xiàn)
1.信號(hào)包括待處理信號(hào)和被阻塞信號(hào)
2.如果產(chǎn)生了一個(gè)被阻塞的信號(hào),它一直保留待處理,直到被解除阻塞。
3.系統(tǒng)保存每一個(gè)進(jìn)程如何處理每一種可能的信號(hào)的信息。
4.系統(tǒng)判斷進(jìn)程是希望忽略這個(gè)信號(hào)還是讓內(nèi)核處理。進(jìn)程通過(guò)執(zhí)行系統(tǒng)調(diào)用改變?nèi)笔〉男盘?hào)處理。
對(duì)信號(hào)的處理
1.初始化信號(hào)集,只有在信號(hào)集里面的信號(hào)才會(huì)被考慮
2.安裝信號(hào)處理器。所謂信號(hào)處理器,就是指定了一些對(duì)信號(hào)的處理方法。在安裝的時(shí)候,一定要對(duì)特定的信號(hào)賦予正確的信號(hào)處理函數(shù)。
信號(hào)相關(guān)函數(shù)
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);為進(jìn)程安裝信號(hào)處理器,struct sigaction數(shù)據(jù)結(jié)構(gòu)是用來(lái)保存信號(hào)處理器的相關(guān)信息。
int sigemptyset(sigset_t *set);將信號(hào)集合清空。
int sigfillset(sigset_t *set);將信號(hào)集合設(shè)置成包含所有的信號(hào),在對(duì)信號(hào)進(jìn)行操作以前一定要對(duì)信號(hào)集進(jìn)行初始化。
int sigaddset(sigset_t *set, int signo);向信號(hào)集中加入signo對(duì)應(yīng)的新信號(hào)。
int sigdelset(sigset_t *set, int signo);從信號(hào)集中刪除signo對(duì)應(yīng)的一個(gè)信號(hào)。
int sigismember(const sigset_t *set, int signo);判斷某個(gè)信號(hào)是否在信號(hào)集中。
int sigprocmask(int how,const sigset_t *set, sigset_t *oset);設(shè)置進(jìn)程的信號(hào)屏蔽碼。信號(hào)屏蔽碼可以用來(lái)在某段時(shí)間內(nèi)阻塞一些信號(hào)集中的信號(hào)。
管道通信:是最古老的Unix IPC工具,一個(gè)進(jìn)程從管道一頭寫(xiě)數(shù)據(jù),另一個(gè)進(jìn)程從管道另一頭讀數(shù)據(jù),以實(shí)現(xiàn)它們之間通信的共享方式,又稱(chēng)pipe文件。由于發(fā)送和接收都是利用管道進(jìn)行通信的,故稱(chēng)為管道通信。通信方式是單向的。管道類(lèi)型分為:無(wú)名管道、命名管道
管道通信的思想
1.發(fā)送進(jìn)程可以源源不斷的從pipe一端寫(xiě)入數(shù)據(jù)流,在規(guī)定的pipe文件的最大長(zhǎng)度(如4096字節(jié))范圍內(nèi),每次寫(xiě)入的信息長(zhǎng)度是可變的。
2.接收進(jìn)程在需要時(shí)可以從pipe的另一端讀出數(shù)據(jù),讀出單位長(zhǎng)度也是可變的。
基本管道調(diào)用函數(shù)
int do_pipe(int *fd);創(chuàng)建管道
static int pipe_release(struct inode *inode, int decr, int decw);管道釋放
無(wú)名管道II
顯示了每一個(gè)file數(shù)據(jù)結(jié)構(gòu)包含了不同的文件操作例程的向量表的指針:一個(gè)用于寫(xiě),另一個(gè)從管道中讀。這掩蓋了和通用的讀寫(xiě)普通文件的系統(tǒng)調(diào)用的不同。當(dāng)寫(xiě)進(jìn)程向管道中寫(xiě)的時(shí)候,字節(jié)拷貝到了共享的數(shù)據(jù)頁(yè),當(dāng)從管道中讀的時(shí)候,字節(jié)從共享頁(yè)中拷貝出來(lái)。
命名管道:又名FIFO,它不是臨時(shí)的對(duì)象,而是文件系統(tǒng)中的實(shí)體,可以用mkfifo命令創(chuàng)建。系統(tǒng)必須處理在寫(xiě)進(jìn)程打開(kāi)FIFO之前打開(kāi)FIFO讀的進(jìn)程,以及在寫(xiě)進(jìn)程寫(xiě)數(shù)據(jù)之前讀的進(jìn)程。它使用和無(wú)名管道一樣的數(shù)據(jù)結(jié)構(gòu)和操作。
???????(寫(xiě)入端)[Fd1]→pipe(fd)→[Fd0](讀出端)
信號(hào)量:信號(hào)量(Semaphore)和信號(hào)是不同的東西,信號(hào)是實(shí)現(xiàn)約定的固定的值,而信號(hào)量是一個(gè)變量記錄著某些特定信息,它的使用主要是用來(lái)保護(hù)共享資源,使得該資源在一個(gè)時(shí)刻只讓一個(gè)進(jìn)程擁有。
信號(hào)量的數(shù)據(jù)結(jié)構(gòu):使用semid_ds數(shù)據(jù)結(jié)構(gòu)表達(dá)信號(hào)量。系統(tǒng)中所有的semid_ds數(shù)據(jù)結(jié)構(gòu)都由semary指針向量表指向。每一個(gè)信號(hào)燈數(shù)組中都有sem_nsems,通過(guò)sem_base指向的一個(gè)sem數(shù)據(jù)結(jié)構(gòu)來(lái)描述
信號(hào)量機(jī)制的實(shí)現(xiàn)
1.對(duì)信號(hào)量的操作只有兩個(gè):P、V。
2.為了在邏輯上便于組織信號(hào)量,信號(hào)量機(jī)制中有一個(gè)概念是信號(hào)量組。我們?cè)谝粋€(gè)信號(hào)量組中創(chuàng)建相關(guān)的信號(hào)量,這樣邏輯上清晰也便于管理。
3.在使用之前同樣需要對(duì)他們進(jìn)行初始化:生成或打開(kāi)信號(hào)量組,向其中生成或刪除指定的信號(hào)量。
4.一個(gè)信號(hào)量必須屬于一個(gè)信號(hào)量組,否則不能被系統(tǒng)所使用。
5.信號(hào)量和信號(hào)量組是不會(huì)被系統(tǒng)所自動(dòng)清理的,所以在進(jìn)程退出前,需要及時(shí)清理生成的那些信號(hào)量。
信號(hào)量的相關(guān)函數(shù)
int semget(key_t key, int nsems, int semflg);創(chuàng)建一個(gè)新的信號(hào)量組或獲取一個(gè)已經(jīng)存在的信號(hào)量組。
int semop(int semid, struct sembuf *sop, int nsops);一次對(duì)一個(gè)或多個(gè)信號(hào)量進(jìn)行操作,用于P、V操作。
Int semctl(int sem_id, int semnum, int cmd, union semun arg);用來(lái)獲取一些信號(hào)量的使用信息或者是來(lái)對(duì)信號(hào)量進(jìn)行控制。
共享內(nèi)存
????共享內(nèi)存是進(jìn)程通信的一個(gè)重要方法,為進(jìn)程提供了直接通信的手段。操作系統(tǒng)中一個(gè)或多個(gè)進(jìn)程通過(guò)同時(shí)出現(xiàn)在它們的虛擬地址空間的內(nèi)存通訊,該虛擬內(nèi)存被每個(gè)共享進(jìn)程的頁(yè)表所引用,它們的地址無(wú)需相同。進(jìn)程對(duì)共享內(nèi)存的訪(fǎng)問(wèn)是受控的,信號(hào)量等機(jī)制實(shí)現(xiàn)了共享內(nèi)存訪(fǎng)問(wèn)的同步
共享內(nèi)存的簡(jiǎn)單原理
每一個(gè)新創(chuàng)建的內(nèi)存區(qū)域都用一個(gè)shmid_ds數(shù)據(jù)結(jié)構(gòu)來(lái)表達(dá)。這些數(shù)據(jù)結(jié)構(gòu)保存在shm_segs向量表中。Shmid_ds數(shù)據(jù)結(jié)構(gòu)描述了這個(gè)共享內(nèi)存取有多大、多少個(gè)進(jìn)程在使用它以及共享內(nèi)存如何映射到它們的地址空間。由共享內(nèi)存的創(chuàng)建者來(lái)控制對(duì)于這塊內(nèi)存的訪(fǎng)問(wèn)權(quán)限和它的key是公開(kāi)或私有。如果有足夠的權(quán)限它也可以把共享內(nèi)存鎖定在物理內(nèi)存中。每一個(gè)希望共享這塊內(nèi)存的進(jìn)程必須通過(guò)系統(tǒng)調(diào)用粘附(attach)到虛擬內(nèi)存。這為該進(jìn)程創(chuàng)建了一個(gè)新的描述這塊共享內(nèi)存的vm_area_struct數(shù)據(jù)結(jié)構(gòu)。進(jìn)程可以選擇共享內(nèi)存在它的虛擬地址空間的位置或者由Linux選擇一塊足夠的的空閑區(qū)域。這個(gè)新的vm_area_struct結(jié)構(gòu)放在由shmid_ds指向的vm_area_struct列表中。通過(guò)vm_next_shared和vm_prev_shared把它們連在一起。
共享內(nèi)存的基本函數(shù)
int shmget(key_t key,int size,int shmflg);建立新的共享內(nèi)存或一個(gè)已存在的共享內(nèi)存描述字
void *shmat(int shmid,const void *shmaddr,int shmflg);將物理共享內(nèi)存粘附到進(jìn)程虛擬地址空間
int shmdt(const void *shmaddr);進(jìn)程從其虛擬地址空間分離共享內(nèi)存
int shmctl(int shmid,int cmd,struct shmid_ds *buf);查詢(xún)及設(shè)置一個(gè)共享內(nèi)存
共享內(nèi)存機(jī)制的實(shí)現(xiàn)
在使用一個(gè)共享內(nèi)存之前我們調(diào)用shmat得到共享內(nèi)存的開(kāi)始地址,使用結(jié)束以后我們使用
shmdt斷開(kāi)這個(gè)內(nèi)存。
進(jìn)程通過(guò)系統(tǒng)調(diào)用粘附到虛擬內(nèi)存,即創(chuàng)建了一個(gè)新的描述這塊共享內(nèi)存的vm_area_struct數(shù)據(jù)結(jié)構(gòu),這個(gè)新的vm_area_struct結(jié)構(gòu)放在由shmid_ds指向的vm_area_struct列表中。通過(guò)vm_next_shared和vm_prev_shared把它們連在一起。
虛擬內(nèi)存在粘附的時(shí)候其實(shí)并沒(méi)有創(chuàng)建,而發(fā)生在第一個(gè)進(jìn)程試圖訪(fǎng)問(wèn)它的時(shí)候。
第一個(gè)訪(fǎng)問(wèn)共享內(nèi)存頁(yè)的進(jìn)程使得這一頁(yè)被創(chuàng)建,而隨后訪(fǎng)問(wèn)的其他進(jìn)程使得此頁(yè)被加到它們的虛擬地址空間。
當(dāng)進(jìn)程不再需要共享虛擬內(nèi)存的時(shí)候,它們從中分離出來(lái)。只要仍舊有其他進(jìn)程在使用這塊內(nèi)存,這種分離只是影響當(dāng)前的進(jìn)程。
當(dāng)共享這塊內(nèi)存的最后一個(gè)進(jìn)程從中分離出的時(shí)候,共享內(nèi)存當(dāng)前在物理內(nèi)存中的頁(yè)被釋放
消息隊(duì)列:消息隊(duì)列是比較高級(jí)的一種進(jìn)程間通信方法,實(shí)現(xiàn)一個(gè)或多個(gè)進(jìn)程間message傳送,一個(gè)消息隊(duì)列可以被多個(gè)進(jìn)程所共享(IPC就是在這個(gè)基礎(chǔ)上進(jìn)行的);如果一個(gè)進(jìn)程的消息太多一個(gè)消息隊(duì)列放不下,也可以用多于一個(gè)的消息隊(duì)列(不過(guò)可能管理會(huì)比較復(fù)雜)。
消息隊(duì)列的基本函數(shù)
int msgget(key_t key, int msgflg);獲取一個(gè)存在的消息隊(duì)列的ID,或者是根據(jù)跟定的權(quán)限創(chuàng)建一個(gè)消息隊(duì)列。
int msgctl(int msqid, int cmd, struct msqid_ds *buf);用來(lái)從msqid_ds中獲取很多消息隊(duì)列本身的信息。
int msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg);用于向隊(duì)列發(fā)送消息。
int msgrcv(int msqid, void *msgp, size_t msgsz, long int msgtyp, intmsgflg);從隊(duì)列中接收消息。
消息隊(duì)列的實(shí)現(xiàn)機(jī)制
消息隊(duì)列,是一個(gè)隊(duì)列的結(jié)構(gòu),隊(duì)列里面的內(nèi)容由用戶(hù)進(jìn)程自己定義。實(shí)際上,隊(duì)列里面記錄的是指向用戶(hù)自定義結(jié)構(gòu)的指針和結(jié)構(gòu)的大小。要使用message queue,首先要通過(guò)系統(tǒng)調(diào)用(msgget)產(chǎn)生一個(gè)隊(duì)列,然后,進(jìn)程可以用msgsnd發(fā)送消息到這個(gè)隊(duì)列,消息就是如上所說(shuō)的結(jié)構(gòu)。別的進(jìn)程用msgrcv讀取。消息隊(duì)列一旦產(chǎn)生,除非明確的刪除(某個(gè)有權(quán)限的進(jìn)程或者用ipcrm命令)或者系統(tǒng)重啟。否則,產(chǎn)生的隊(duì)列會(huì)一直保留在系統(tǒng)中。而且,只要有權(quán)限,就可以對(duì)隊(duì)列進(jìn)行操作。消息隊(duì)列和管道很相似,實(shí)際上,管道就是用戶(hù)消息為1個(gè)字節(jié)的隊(duì)列。
消息隊(duì)列的寫(xiě)進(jìn)程
每一次一個(gè)進(jìn)程試圖向?qū)戧?duì)列寫(xiě)消息,它的有效用戶(hù)和組的標(biāo)識(shí)符就要和隊(duì)列的ipc_perm數(shù)據(jù)結(jié)構(gòu)的模式比較。如果進(jìn)程可以想這個(gè)隊(duì)列寫(xiě),則消息會(huì)從進(jìn)程的地址空間寫(xiě)到msg數(shù)據(jù)結(jié)構(gòu),放到消息隊(duì)列的最后。每一個(gè)消息都帶有進(jìn)程間約定的,應(yīng)用程序指定類(lèi)型的標(biāo)記。
消息隊(duì)列的讀進(jìn)程
從隊(duì)列中讀是一個(gè)相似的過(guò)程。進(jìn)程的訪(fǎng)問(wèn)權(quán)限一樣被檢查。一個(gè)讀進(jìn)程可以選擇是不管消息的類(lèi)型從隊(duì)列中讀取第一條消息還是選擇特殊類(lèi)型的消息。如果沒(méi)有符合條件的消息,讀進(jìn)程會(huì)被加到消息隊(duì)列的讀等待進(jìn)程,然后運(yùn)行調(diào)度程序。當(dāng)一個(gè)新的消息寫(xiě)到隊(duì)列的時(shí)候,這個(gè)進(jìn)程會(huì)被喚醒,繼續(xù)運(yùn)行。
消息隊(duì)列的簡(jiǎn)單流程
發(fā)送進(jìn)程?????????????????????????????接收流程
Send(m)??????????????????????????????Receive(m )
?? Begin?????????????????????????????????begin
???向系統(tǒng)申請(qǐng)一個(gè)消息緩沖區(qū)??????????????P(SM) 等待接的消息的個(gè)數(shù)
???P(mutex) 使用公用緩沖區(qū)???????????????P(mutex) 使用公用緩沖區(qū)
???將發(fā)送區(qū)消息m送入新申請(qǐng)的消息緩沖區(qū)??摘下消息隊(duì)列中的消息m
???把消息緩沖區(qū)掛入接收進(jìn)程的消息隊(duì)列?????將消息隊(duì)列m從緩沖區(qū)復(fù)制到接收區(qū)
???V(mutex)釋放緩沖區(qū)????????????????????釋放緩沖區(qū)
???V(SM)向接收進(jìn)程發(fā)送消息??????????????V(mutex) 釋放公用緩沖區(qū)
??End?????????????????????????????????????end
Socket
獨(dú)立于具體協(xié)議的網(wǎng)絡(luò)編程接口;
在ISO模型中,主要位于會(huì)話(huà)層和傳輸層。
網(wǎng)絡(luò)編程接口:UNIX BSD的套接字(socket)、UNIX System V的TLI
BSD Socket(伯克立套接字)是通過(guò)標(biāo)準(zhǔn)的UNIX文件描述符和其它程序通訊的一個(gè)方法,目前已經(jīng)被廣泛移植到各個(gè)平臺(tái)。
Socket的類(lèi)型
流式套接字:提供了一個(gè)面向連接,可靠的數(shù)據(jù)傳輸服務(wù),數(shù)據(jù)無(wú)差錯(cuò),無(wú)重復(fù)地發(fā)送且按發(fā)送順序接收.內(nèi)設(shè)流量控制,避免數(shù)據(jù)流超限;數(shù)據(jù)被看作是字節(jié)流,無(wú)長(zhǎng)度限制,FTP即用此
數(shù)據(jù)報(bào)套接字:提供了一個(gè)無(wú)連接服務(wù).數(shù)據(jù)包以獨(dú)立包形式被發(fā)送,不提供無(wú)差錯(cuò)保證,數(shù)據(jù)可能丟失或重復(fù),并且接受順序無(wú)序,網(wǎng)絡(luò)文件系統(tǒng)NFS
原始套接字(SOCK_RAW):該接口允許對(duì)較低層次協(xié)議,如IP,ICMP直接訪(fǎng)問(wèn)
基本套接字調(diào)用
創(chuàng)建套接字???????????????socket();
綁定本機(jī)端口???????????bind();
建立連接???????????????????connect();
接受連接???????????????????accept();
監(jiān)聽(tīng)端口???????????????????listen();
數(shù)據(jù)傳輸???????????????????send(), recv()等
關(guān)閉套接字???????????????close();
Socket相關(guān)數(shù)據(jù)結(jié)構(gòu)
struct sockaddr_in
??????????{
??????????????????short int??? sin_family;????/*通信類(lèi)型*/
??????????????????unsigned short int sin_port;???????/*端口號(hào),網(wǎng)絡(luò)直接順序*/
??????????????????struct in_addr??
???????? }
總結(jié)
以上是生活随笔為你收集整理的关于进程间通信的学习心得的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 《感兴二首》是哪个时期的作品?
- 下一篇: 等离子原理?