linux基礎(chǔ)復(fù)習(xí)(8)進(jìn)程通信
數(shù)據(jù)傳輸:一個(gè)進(jìn)程需要將它的數(shù)據(jù)發(fā)送給另一個(gè)進(jìn)程,發(fā)送的數(shù)據(jù)量在一個(gè)字節(jié)到幾兆字節(jié)之間。
本文引用地址:http://www.2s4d.com/article/201610/305812.htm共享數(shù)據(jù):多個(gè)進(jìn)程想要操作共享數(shù)據(jù),一個(gè)進(jìn)程對共享數(shù)據(jù)的修改,別的進(jìn)程應(yīng)該立刻看到。
通知事件:一個(gè)進(jìn)程需要向另一個(gè)或一組進(jìn)程發(fā)送消息,通知它(它們)發(fā)生了某種事件(如進(jìn)程終止時(shí)要通知父進(jìn)程)。
資源共享:多個(gè)進(jìn)程之間共享同樣的資源。為了作到這一點(diǎn),需要內(nèi)核提供鎖和同步機(jī)制。
進(jìn)程控制:有些進(jìn)程希望完全控制另一個(gè)進(jìn)程的執(zhí)行(如Debug進(jìn)程),此時(shí)控制進(jìn)程希望能夠攔截另一個(gè)進(jìn)程的所有陷入和異常,并能夠及時(shí)知道它的狀態(tài)改變。
UNIX 進(jìn)程間通信(IPC)方式包括管道、FIFO、信號。
Linux 中使用較多的進(jìn)程間通信方式主要有以下幾種。
(1)管道(Pipe)及有名管道(named pipe):管道可用于具有親緣關(guān)系進(jìn)程間的通信,有名管道,除具有管道所具有的功能外,它還允許無親緣關(guān)系進(jìn)程間的通信。
(2)信號(Signal):信號是在軟件層次上對中斷機(jī)制的一種模擬,它是比較復(fù)雜的通信方式,用于通知接受進(jìn)程有某事件發(fā)生,一個(gè)進(jìn)程收到一個(gè)信號與處理器收到一個(gè)中斷請求效果上可以說是一樣的。
(3)消息隊(duì)列:消息隊(duì)列是消息的鏈接表,包括Posix 消息隊(duì)列systemV 消息隊(duì)列。它克服了前兩種通信方式中信息量有限的缺點(diǎn),具有寫權(quán)限的進(jìn)程可以向消息隊(duì)列中按照一定的規(guī)則添加新消息;對消息隊(duì)列有讀權(quán)限的進(jìn)程則可以從消息隊(duì)列中讀取消息。
(4)共享內(nèi)存:可以說這是最有用的進(jìn)程間通信方式。它使得多個(gè)進(jìn)程可以訪問同一塊內(nèi)存空間,不同進(jìn)程可以及時(shí)看到對方進(jìn)程中對共享內(nèi)存中數(shù)據(jù)的更新。這種通信方式需要依靠某種同步機(jī)制,如互斥鎖和信號量等。
(5)信號量:主要作為進(jìn)程間以及同一進(jìn)程不同線程之間的同步手段。
(6)套接字(Socket):這是一種更為一般的進(jìn)程間通信機(jī)制,它可用于不同機(jī)器之間的進(jìn)程間通信,應(yīng)用非常廣泛。
[b]管道通信[/b]
普通的Linux shell都允許重定向,而重定向使用的就是管道。例如:
ps | grep vsftpd
管道是單向的、先進(jìn)先出的、無結(jié)構(gòu)的、固定大小的字節(jié)流,它把一個(gè)進(jìn)程的標(biāo)準(zhǔn)輸出和另一個(gè)進(jìn)程的標(biāo)準(zhǔn)輸入連接在一起。寫進(jìn)程在管道的尾端寫入數(shù)據(jù),讀進(jìn)程在管道的首端讀出數(shù)據(jù)。數(shù)據(jù)讀出后將從管道中移走,其它讀進(jìn)程都不能再讀到這些數(shù)據(jù)。管道提供了簡單的流控制機(jī)制。進(jìn)程試圖讀空管道時(shí),在有數(shù)據(jù)寫入管道前,進(jìn)程將一直阻塞。同樣,管道已經(jīng)滿時(shí),進(jìn)程再試圖寫管道,在其它進(jìn)程從管道中移走數(shù)據(jù)之前,寫進(jìn)程將一直阻塞。
管道主要用于不同進(jìn)程間通信。
創(chuàng)建一個(gè)簡單的管道,可以使用系統(tǒng)調(diào)用pipe( )。它接受一個(gè)參數(shù),也就是一個(gè)包括兩個(gè)整數(shù)的數(shù)組。如果系統(tǒng)調(diào)用成功,此數(shù)組將包括管道使用的兩個(gè)文件描述符。創(chuàng)建一個(gè)管道之后,一般情況下進(jìn)程將產(chǎn)生一個(gè)新的進(jìn)程。
系統(tǒng)調(diào)用:pipe( );
原型:int pipe( int fd[2] );
返回值:如果系統(tǒng)調(diào)用成功,返回0。如果系統(tǒng)調(diào)用失敗返回- 1:
errno = EMFILE (沒有空閑的文件描述符)
EMFILE (系統(tǒng)文件表已滿)
EFAULT (fd數(shù)組無效)
注意:fd[0] 用于讀取管道,fd[1] 用于寫入管道。
#i nclude
#i nclude
#i nclude
#i nclude
int main()
{
int pipe_fd[2];
if(pipe(pipe_fd)0)
{
printf(pipe create errorn);
return -1;
}
else
printf(pipe create successn);
close(pipe_fd[0]);
close(pipe_fd[1]);
}
管道主要用于不同進(jìn)程間通信。實(shí)際上,通常先創(chuàng)建一個(gè)管道,再通過fork函數(shù)創(chuàng)建一個(gè)子進(jìn)程。
可以通過打開兩個(gè)管道來創(chuàng)建一個(gè)雙向的管道。但需要在子進(jìn)程中正確地設(shè)置文件描述符。
必須在系統(tǒng)調(diào)用fork( )中調(diào)用pipe( ),否則子進(jìn)程將不會繼承文件描述符。
當(dāng)使用半雙工管道時(shí),任何關(guān)聯(lián)的進(jìn)程都必須共享一個(gè)相關(guān)的祖先進(jìn)程。因?yàn)楣艿来嬖谟谙到y(tǒng)內(nèi)核之中,所以任何不在創(chuàng)建管道的進(jìn)程的祖先進(jìn)程之中的進(jìn)程都將無法尋址它。而在命名管道中卻不是這樣。
與linux中文件操作有文件流的標(biāo)準(zhǔn)I/O一樣,管道的操作也支持基于文件流的模式。接口函數(shù)如下
庫函數(shù):popen();
原型: FILE *popen ( char *command, char *type);
返回值:如果成功,返回一個(gè)新的文件流。如果無法創(chuàng)建進(jìn)程或者管道,返回NULL。
管道中數(shù)據(jù)流的方向是由第二個(gè)參數(shù)type控制的。此參數(shù)可以是r或者w,分別代表讀或?qū)憽5荒芡瑫r(shí)為讀和寫。在Linux系統(tǒng)下,管道將會以參數(shù)type中第一個(gè)字符代表的方式打開。所以,如果你在參數(shù)type中寫入rw,管道將會以讀的方式打開。
使用popen()創(chuàng)建的管道必須使用pclose( )關(guān)閉。其實(shí),popen/pclose和標(biāo)準(zhǔn)文件輸入/輸出流中的fopen() / fclose()十分相似。
庫函數(shù): pclose();
原型: int pclose( FILE *stream );
返回值: 返回系統(tǒng)調(diào)用wait4( )的狀態(tài)。
如果stream無效,或者系統(tǒng)調(diào)用wait4( )失敗,則返回 -1。
注意此庫函數(shù)等待管道進(jìn)程運(yùn)行結(jié)束,然后關(guān)閉文件流。
庫函數(shù)pclose( )在使用popen( )創(chuàng)建的進(jìn)程上執(zhí)行wait4( )函數(shù)。當(dāng)它返回時(shí),它將破壞管道和文件系統(tǒng)。
#i nclude
#i nclude
#i nclude
#i nclude
#define BUFSIZE 1024
int main()
{
FILE *fp;
char *cmd = ps -ef;
char buf[BUFSIZE];
buf[BUFSIZE] = '