Linux系統(tǒng)管道和有名管道的通信機(jī)制
Linux 進(jìn)程間通信的幾種主要手段。其中管道和有名管道是最早的進(jìn)程間通信機(jī)制之一,管道可用于具有親緣關(guān)系進(jìn)程間的通信,有名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關(guān)系進(jìn)程間的通信。 認(rèn)清管道和有名管道的讀寫規(guī)則是在程序中應(yīng)用它們的關(guān)鍵,本文在詳細(xì)討論了管道和有名管道的通信機(jī)制的基礎(chǔ)上,用實例對其讀寫規(guī)則進(jìn)行了程序驗證,這樣做有利于增強(qiáng)讀者對讀寫規(guī)則的感性認(rèn)識,同時也提供了應(yīng)用范例。
1、 管道概述及相關(guān)API應(yīng)用
1.1 管道相關(guān)的關(guān)鍵概念
管道是Linux支持的最初Unix IPC形式之一,具有以下特點:
管道是半雙工的,數(shù)據(jù)只能向一個方向流動;需要雙方通信時,需要建立起兩個管道;
只能用于父子進(jìn)程或者兄弟進(jìn)程之間(具有親緣關(guān)系的進(jìn)程);
單獨構(gòu)成一種獨立的文件系統(tǒng):管道對于管道兩端的進(jìn)程而言,就是一個文件,但它不是普通的文件,它不屬于某種文件系統(tǒng),而是自立門戶,單獨構(gòu)成一種文件系統(tǒng),并且只存在與內(nèi)存中。
數(shù)據(jù)的讀出和寫入:一個進(jìn)程向管道中寫的內(nèi)容被管道另一端的進(jìn)程讀出。寫入的內(nèi)容每次都添加在管道緩沖區(qū)的末尾,并且每次都是從緩沖區(qū)的頭部讀出數(shù)據(jù)。
1.2 管道的創(chuàng)建:
#include int pipe(int fd[2])
該函數(shù)創(chuàng)建的管道的兩端處于一個進(jìn)程中間,在實際應(yīng)用中沒有太大意義,因此,一個進(jìn)程在由pipe()創(chuàng)建管道后,一般再fork一個子進(jìn)程,然后通過管道實現(xiàn)父子進(jìn)程間的通信(因此也不難推出,只要兩個進(jìn)程中存在親緣關(guān)系,這里的親緣關(guān)系指的是具有共同的祖先,都可以采用管道方式來進(jìn)行通信)。
1.3 管道的讀寫規(guī)則:
管道兩端可分別用描述字fd[0]以及fd[1]來描述,需要注意的是,管道的兩端是固定了任務(wù)的。即一端只能用于讀,由描述字fd[0]表示,稱其為管道讀端;另一端則只能用于寫,由描述字fd[1]來表示,稱其為管道寫端。如果試圖從管道寫端讀取數(shù)據(jù),或者向管道讀端寫入數(shù)據(jù)都將導(dǎo)致錯誤發(fā)生。一般文件的I/O函數(shù)都可以用于管道,如close、read、write等等。
從管道中讀取數(shù)據(jù):如果管道的寫端不存在,則認(rèn)為已經(jīng)讀到了數(shù)據(jù)的末尾,讀函數(shù)返回的讀出字節(jié)數(shù)為0;當(dāng)管道的寫端存在時,如果請求的字節(jié)數(shù)目大于PIPE_BUF,則返回管道中現(xiàn)有的數(shù)據(jù)字節(jié)數(shù),如果請求的字節(jié)數(shù)目不大于PIPE_BUF,則返回管道中現(xiàn)有數(shù)據(jù)字節(jié)數(shù)(此時,管道中數(shù)據(jù)量小于請求的數(shù)據(jù)量);或者返回請求的字節(jié)數(shù)(此時,管道中數(shù)據(jù)量不小于請求的數(shù)據(jù)量)。注:(PIPE_BUF在include/Linux/limits.h中定義,不同的內(nèi)核版本可能會有所不同。Posix.1要求PIPE_BUF至少為512字節(jié),red hat 7.2中為4096)。
關(guān)于管道的讀規(guī)則驗證:
* readtest.c * #include #include #include main() { int pipe_fd[2]; pid_t pid; char r_buf[100]; char w_buf[4]; char* p_wbuf; int r_num; int cmd; memset(r_buf,0,sizeof(r_buf)); memset(w_buf,0,sizeof(r_buf)); p_wbuf=w_buf; if(pipe(pipe_fd)<0) { printf("pipe create errorn"); return -1; } if((pid=fork())==0) { printf("n"); close(pipe_fd[1]); sleep(3);//確保父進(jìn)程關(guān)閉寫端 r_num=read(pipe_fd[0],r_buf,100); printf( "read num is %d the data read from the pipe is %dn",r_num,atoi(r_buf)); close(pipe_fd[0]); exit(); } else if(pid>0) { close(pipe_fd[0]);//read strcpy(w_buf,"111"); if(write(pipe_fd[1],w_buf,4)!=-1) printf("parent write overn"); close(pipe_fd[1]);//write printf("parent close fd[1] overn"); sleep(10); } }
程序輸出結(jié)果:
* parent write over * parent close fd[1] over * read num is 4 the data read from the pipe is 111
附加結(jié)論:管道寫端關(guān)閉后,寫入的數(shù)據(jù)將一直存在,直到讀出為止。
向管道中寫入數(shù)據(jù):向管道中寫入數(shù)據(jù)時,Linux將不保證寫入的原子性,管道緩沖區(qū)一有空閑區(qū)域,寫進(jìn)程就會試圖向管道寫入數(shù)據(jù)。如果讀進(jìn)程不讀走管道緩沖區(qū)中的數(shù)據(jù),那么寫操作將一直阻塞。
注:只有在管道的讀端存在時,向管道中寫入數(shù)據(jù)才有意義。否則,向管道中寫入數(shù)據(jù)的進(jìn)程將收到內(nèi)核傳來的SIFPIPE信號,應(yīng)用程序可以處理該信號,也可以忽略(默認(rèn)動作則是應(yīng)用程序終止)。對管道的寫規(guī)則的驗證1:寫端對讀端存在的依賴性
#include #include main() { int pipe_fd[2]; pid_t pid; char r_buf[4]; char* w_buf; int writenum; int cmd; memset(r_buf,0,sizeof(r_buf)); if(pipe(pipe_fd)<0) { printf("pipe create errorn"); return -1; } if((pid=fork())==0) { close(pipe_fd[0]); close(pipe_fd[1]); sleep(10); exit(); } else if(pid>0) { sleep(1); //等待子進(jìn)程完成關(guān)閉讀端的操作 close(pipe_fd[0]);//write w_buf="111"; if((writenum=write(pipe_fd[1],w_buf,4))==-1) printf("write to pipe errorn"); else printf("the bytes write to pipe is %d n", writenum); close(pipe_fd[1]); } }
則輸出結(jié)果為: Broken pipe,原因就是該管道以及它的所有fork()產(chǎn)物的讀端都已經(jīng)被關(guān)閉。如果在父進(jìn)程中保留讀端,即在寫完pipe后,再關(guān)閉父進(jìn)程的讀端,也會正常寫入pipe,讀者可自己驗證一下該結(jié)論。因此,在向管道寫入數(shù)據(jù)時,至少應(yīng)該存在某一個進(jìn)程,其中管道讀端沒有被關(guān)閉,否則就會出現(xiàn)上述錯誤(管道斷裂,進(jìn)程收到了SIGPIPE信號,默認(rèn)動作是進(jìn)程終止)對管道的寫規(guī)則的驗證2:Linux不保證寫管道的原子性驗證
#include #include #include main(int argc,char**argv) { int pipe_fd[2]; pid_t pid; char r_buf[4096]; char w_buf[4096*2]; int writenum; int rnum; memset(r_buf,0,sizeof(r_buf)); if(pipe(pipe_fd)<0) { printf("pipe create errorn"); return -1; } if((pid=fork())==0) { close(pipe_fd[1]); while(1) { sleep(1); rnum=read(pipe_fd[0],r_buf,1000); printf("child: readnum is %dn",rnum); } close(pipe_fd[0]); exit(); } else if(pid>0) { close(pipe_fd[0]);//write memset(r_buf,0,sizeof(r_buf)); if((writenum=write(pipe_fd[1],w_buf,1024))==-1) printf("write to pipe errorn"); else printf("the bytes write to pipe is %d n", writenum); writenum=write(pipe_fd[1],w_buf,4096); close(pipe_fd[1]); } }
輸出結(jié)果:
the bytes write to pipe 1000 the bytes write to pipe 1000 //注意,此行輸出說明了寫入的非原子性 the bytes write to pipe 1000 the bytes write to pipe 1000 the bytes write to pipe 1000 the bytes write to pipe 120 //注意,此行輸出說明了寫入的非原子性 the bytes write to pipe 0 the bytes write to pipe 0 ......
結(jié)論:
寫入數(shù)目小于4096時寫入是非原子的!
如果把父進(jìn)程中的兩次寫入字節(jié)數(shù)都改為5000,則很容易得出下面結(jié)論:
寫入管道的數(shù)據(jù)量大于4096字節(jié)時,緩沖區(qū)的空閑空間將被寫入數(shù)據(jù)(補(bǔ)齊),直到寫完所有數(shù)據(jù)為止,如果沒有進(jìn)程讀數(shù)據(jù),則一直阻塞。
1.4 管道應(yīng)用實例:
實例一:用于shell
管道可用于輸入輸出重定向,它將一個命令的輸出直接定向到另一個命令的輸入。比如,當(dāng)在某個shell程序(Bourne shell或C shell等)鍵入who│wc -l后,相應(yīng)shell程序?qū)?chuàng)建who以及wc兩個進(jìn)程和這兩個進(jìn)程間的管道??紤]命令行:$kill -l
$kill -l | grep SIGRTMIN 運行結(jié)果如下:
30) SIGPWR 31) SIGSYS 32) SIGRTMIN 33) SIGRTMIN+1 34) SIGRTMIN+2 35) SIGRTMIN+3 36) SIGRTMIN+4 37) SIGRTMIN+5 38) SIGRTMIN+6 39) SIGRTMIN+7 40) SIGRTMIN+8 41) SIGRTMIN+9 42) SIGRTMIN+10 43) SIGRTMIN+11 44) SIGRTMIN+12 45) SIGRTMIN+13 46) SIGRTMIN+14 47) SIGRTMIN+15 48) SIGRTMAX-15 49) SIGRTMAX-14
實例二:用于具有親緣關(guān)系的進(jìn)程間通信
下面例子給出了管道的具體應(yīng)用,父進(jìn)程通過管道發(fā)送一些命令給子進(jìn)程,子進(jìn)程解析命令,并根據(jù)命令作相應(yīng)處理。
#include #include main() { int pipe_fd[2]; pid_t pid; char r_buf[4]; char** w_buf[256]; int childexit=0; int i; int cmd; memset(r_buf,0,sizeof(r_buf)); if(pipe(pipe_fd)<0) { printf("pipe create errorn"); return -1; } if((pid=fork())==0) //子進(jìn)程:解析從管道中獲取的命令,并作相應(yīng)的處理 { printf("n"); close(pipe_fd[1]); sleep(2); while(!childexit) { read(pipe_fd[0],r_buf,4); cmd=atoi(r_buf); if(cmd==0) { printf("child: receive command from parent overn now child process exitn"); childexit=1; } else if(handle_cmd(cmd)!=0) return; sleep(1); } close(pipe_fd[0]); exit(); } else if(pid>0) //parent: send commands to child { close(pipe_fd[0]); w_buf[0]="003"; w_buf[1]="005"; w_buf[2]="777"; w_buf[3]="000"; for(i=0;i<4;i++) write(pipe_fd[1],w_buf,4); close(pipe_fd[1]); } } //下面是子進(jìn)程的命令處理函數(shù)(特定于應(yīng)用): int handle_cmd(int cmd) { if((cmd<0)||(cmd>256)) //suppose child only support 256 commands { printf("child: invalid command n"); return -1; } printf("child: the cmd from parent is %dn", cmd); return 0; }
1.5管道的局限性
管道的主要局限性正體現(xiàn)在它的特點上:
只支持單向數(shù)據(jù)流;
只能用于具有親緣關(guān)系的進(jìn)程之間;
沒有名字;
管道的緩沖區(qū)是有限的(管道制存在于內(nèi)存中,在管道創(chuàng)建時,為緩沖區(qū)分配一個頁面大?。?;
管道所傳送的是無格式字節(jié)流,這就要求管道的讀出方和寫入方必須事先約定好數(shù)據(jù)的格式,比如多少字節(jié)算作一個消息(或命令、或記錄)等等。
2、 有名管道概述及相關(guān)API應(yīng)用
2.1 有名管道相關(guān)的關(guān)鍵概念
管道應(yīng)用的一個重大限制是它沒有名字,因此,只能用于具有親緣關(guān)系的進(jìn)程間通信,在有名管道(named pipe或FIFO)提出后,該限制得到了克服。FIFO不同于管道之處在于它提供一個路徑名與之關(guān)聯(lián),以FIFO的文件形式存在于文件系統(tǒng)中。這樣,即使與FIFO的創(chuàng)建進(jìn)程不存在親緣關(guān)系的進(jìn)程,只要可以訪問該路徑,就能夠彼此通過FIFO相互通信(能夠訪問該路徑的進(jìn)程以及FIFO的創(chuàng)建進(jìn)程之間),因此,通過FIFO不相關(guān)的進(jìn)程也能交換數(shù)據(jù)。值得注意的是,F(xiàn)IFO嚴(yán)格遵循先進(jìn)先出(first in first out),對管道及FIFO的讀總是從開始處返回數(shù)據(jù),對它們的寫則把數(shù)據(jù)添加到末尾。它們不支持諸如lseek()等文件定位操作。
2.2 有名管道的創(chuàng)建
#include #include int mkfifo(const char * pathname, mode_t mode)
該函數(shù)的第一個參數(shù)是一個普通的路徑名,也就是創(chuàng)建后FIFO的名字。第二個參數(shù)與打開普通文件的open()函數(shù)中的mode 參數(shù)相同。如果mkfifo的第一個參數(shù)是一個已經(jīng)存在的路徑名時,會返回EEXIST錯誤,所以一般典型的調(diào)用代碼首先會檢查是否返回該錯誤,如果確實返回該錯誤,那么只要調(diào)用打開FIFO的函數(shù)就可以了。一般文件的I/O函數(shù)都可以用于FIFO,如close、read、write等等。
2.3 有名管道的打開規(guī)則
有名管道比管道多了一個打開操作:open。
FIFO的打開規(guī)則:
如果當(dāng)前打開操作是為讀而打開FIFO時,若已經(jīng)有相應(yīng)進(jìn)程為寫而打開該FIFO,則當(dāng)前打開操作將成功返回;否則,可能阻塞直到有相應(yīng)進(jìn)程為寫而打開該FIFO(當(dāng)前打開操作設(shè)置了阻塞標(biāo)志);或者,成功返回(當(dāng)前打開操作沒有設(shè)置阻塞標(biāo)志)。
如果當(dāng)前打開操作是為寫而打開FIFO時,如果已經(jīng)有相應(yīng)進(jìn)程為讀而打開該FIFO,則當(dāng)前打開操作將成功返回;否則,可能阻塞直到有相應(yīng)進(jìn)程為讀而打開該FIFO(當(dāng)前打開操作設(shè)置了阻塞標(biāo)志);或者,返回ENXIO錯誤(當(dāng)前打開操作沒有設(shè)置阻塞標(biāo)志)。對打開規(guī)則的驗證參見附2。
2.4 有名管道的讀寫規(guī)則
從FIFO中讀取數(shù)據(jù):
約定:如果一個進(jìn)程為了從FIFO中讀取數(shù)據(jù)而阻塞打開FIFO,那么稱該進(jìn)程內(nèi)的讀操作為設(shè)置了阻塞標(biāo)志的讀操作。
如果有進(jìn)程寫打開FIFO,且當(dāng)前FIFO內(nèi)沒有數(shù)據(jù),則對于設(shè)置了阻塞標(biāo)志的讀操作來說,將一直阻塞。對于沒有設(shè)置阻塞標(biāo)志讀操作來說則返回-1,當(dāng)前errno值為EAGAIN,提醒以后再試。
對于設(shè)置了阻塞標(biāo)志的讀操作說,造成阻塞的原因有兩種:當(dāng)前FIFO內(nèi)有數(shù)據(jù),但有其它進(jìn)程在讀這些數(shù)據(jù);另外就是FIFO內(nèi)沒有數(shù)據(jù)。解阻塞的原因則是FIFO中有新的數(shù)據(jù)寫入,不論信寫入數(shù)據(jù)量的大小,也不論讀操作請求多少數(shù)據(jù)量。
讀打開的阻塞標(biāo)志只對本進(jìn)程第一個讀操作施加作用,如果本進(jìn)程內(nèi)有多個讀操作序列,則在第一個讀操作被喚醒并完成讀操作后,其它將要執(zhí)行的讀操作將不再阻塞,即使在執(zhí)行讀操作時,F(xiàn)IFO中沒有數(shù)據(jù)也一樣(此時,讀操作返回0)。如果沒有進(jìn)程寫打開FIFO,則設(shè)置了阻塞標(biāo)志的讀操作會阻塞。
注:如果FIFO中有數(shù)據(jù),則設(shè)置了阻塞標(biāo)志的讀操作不會因為FIFO中的字節(jié)數(shù)小于請求讀的字節(jié)數(shù)而阻塞,此時,讀操作會返回FIFO中現(xiàn)有的數(shù)據(jù)量。
向FIFO中寫入數(shù)據(jù):
約定:如果一個進(jìn)程為了向FIFO中寫入數(shù)據(jù)而阻塞打開FIFO,那么稱該進(jìn)程內(nèi)的寫操作為設(shè)置了阻塞標(biāo)志的寫操作。
對于設(shè)置了阻塞標(biāo)志的寫操作:
當(dāng)要寫入的數(shù)據(jù)量不大于PIPE_BUF時,Linux將保證寫入的原子性。如果此時管道空閑緩沖區(qū)不足以容納要寫入的字節(jié)數(shù),則進(jìn)入睡眠,直到當(dāng)緩沖區(qū)中能夠容納要寫入的字節(jié)數(shù)時,才開始進(jìn)行一次性寫操作。
當(dāng)要寫入的數(shù)據(jù)量大于PIPE_BUF時,Linux將不再保證寫入的原子性。FIFO緩沖區(qū)一有空閑區(qū)域,寫進(jìn)程就會試圖向管道寫入數(shù)據(jù),寫操作在寫完所有請求寫的數(shù)據(jù)后返回。
對于沒有設(shè)置阻塞標(biāo)志的寫操作:
當(dāng)要寫入的數(shù)據(jù)量大于PIPE_BUF時,Linux將不再保證寫入的原子性。在寫滿所有FIFO空閑緩沖區(qū)后,寫操作返回。
當(dāng)要寫入的數(shù)據(jù)量不大于PIPE_BUF時,Linux將保證寫入的原子性。如果當(dāng)前FIFO空閑緩沖區(qū)能夠容納請求寫入的字節(jié)數(shù),寫完后成功返回;如果當(dāng)前FIFO空閑緩沖區(qū)不能夠容納請求寫入的字節(jié)數(shù),則返回EAGAIN錯誤,提醒以后再寫。
對FIFO讀寫規(guī)則的驗證:
下面提供了兩個對FIFO的讀寫程序,適當(dāng)調(diào)節(jié)程序中的很少地方或者程序的命令行參數(shù)就可以對各種FIFO讀寫規(guī)則進(jìn)行驗證。
程序1:寫FIFO的程序
#include #include #include #include #define FIFO_SERVER "/tmp/fifoserver" main(int argc,char** argv) //參數(shù)為即將寫入的字節(jié)數(shù) { int fd; char w_buf[4096*2]; int real_wnum; memset(w_buf,0,4096*2); if((mkfifo(FIFO_SERVER,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST)) printf("cannot create fifoservern"); if(fd==-1) if(errno==ENXIO) printf("open error; no reading processn"); fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0); //設(shè)置非阻塞標(biāo)志 //fd=open(FIFO_SERVER,O_WRONLY,0); //設(shè)置阻塞標(biāo)志 real_wnum=write(fd,w_buf,2048); if(real_wnum==-1) { if(errno==EAGAIN) printf("write to fifo error; try latern"); } else printf("real write num is %dn",real_wnum); real_wnum=write(fd,w_buf,5000); //5000用于測試寫入字節(jié)大于4096時的非原子性 //real_wnum=write(fd,w_buf,4096); //4096用于測試寫入字節(jié)不大于4096時的原子性 if(real_wnum==-1) if(errno==EAGAIN) printf("try latern"); }
程序2:與程序1一起測試寫FIFO的規(guī)則,第一個命令行參數(shù)是請求從FIFO讀出的字節(jié)數(shù)
#include #include #include #include #define FIFO_SERVER "/tmp/fifoserver" main(int argc,char** argv) { char r_buf[4096*2]; int fd; int r_size; int ret_size; r_size=atoi(argv[1]); printf("requred real read bytes %dn",r_size); memset(r_buf,0,sizeof(r_buf)); fd=open(FIFO_SERVER,O_RDONLY|O_NONBLOCK,0); //fd=open(FIFO_SERVER,O_RDONLY,0); //在此處可以把讀程序編譯成兩個不同版本:阻塞版本及非阻塞版本 if(fd==-1) { printf("open %s for read errorn"); exit(); } while(1) { memset(r_buf,0,sizeof(r_buf)); ret_size=read(fd,r_buf,r_size); if(ret_size==-1) if(errno==EAGAIN) printf("no data avlaiblen"); printf("real read bytes %dn",ret_size); sleep(1); } pause(); unlink(FIFO_SERVER); }
程序應(yīng)用說明:
把讀程序編譯成兩個不同版本。
阻塞讀版本:br
以及非阻塞讀版本:nbr
把寫程序編譯成兩個四個版本。
非阻塞且請求寫的字節(jié)數(shù)大于PIPE_BUF版本:nbwg
非阻塞且請求寫的字節(jié)數(shù)不大于PIPE_BUF版本:版本nbw
阻塞且請求寫的字節(jié)數(shù)大于PIPE_BUF版本:bwg
阻塞且請求寫的字節(jié)數(shù)不大于PIPE_BUF版本:版本bw
下面將使用br、nbr、w代替相應(yīng)程序中的阻塞讀、非阻塞讀
驗證阻塞寫操作:
當(dāng)請求寫入的數(shù)據(jù)量大于PIPE_BUF時的非原子性:
nbr 1000 bwg
當(dāng)請求寫入的數(shù)據(jù)量不大于PIPE_BUF時的原子性:
nbr 1000 bw
驗證非阻塞寫操作:
當(dāng)請求寫入的數(shù)據(jù)量大于PIPE_BUF時的非原子性:
nbr 1000 nbwg
請求寫入的數(shù)據(jù)量不大于PIPE_BUF時的原子性:
nbr 1000 nbw
不管寫打開的阻塞標(biāo)志是否設(shè)置,在請求寫入的字節(jié)數(shù)大于4096時,都不保證寫入的原子性。但二者有本質(zhì)區(qū)別:
對于阻塞寫來說,寫操作在寫滿FIFO的空閑區(qū)域后,會一直等待,直到寫完所有數(shù)據(jù)為止,請求寫入的數(shù)據(jù)最終都會寫入FIFO;
而非阻塞寫則在寫滿FIFO的空閑區(qū)域后,就返回(實際寫入的字節(jié)數(shù)),所以有些數(shù)據(jù)最終不能夠?qū)懭搿?/p>
對于讀操作的驗證則比較簡單,不再討論。
2.5 有名管道應(yīng)用實例
在驗證了相應(yīng)的讀寫規(guī)則后,應(yīng)用實例似乎就沒有必要了。
小結(jié):
管道常用于兩個方面:(1)在shell中時常會用到管道(作為輸入輸入的重定向),在這種應(yīng)用方式下,管道的創(chuàng)建對于用戶來說是透明的;(2)用于具有親緣關(guān)系的進(jìn)程間通信,用戶自己創(chuàng)建管道,并完成讀寫操作。
FIFO可以說是管道的推廣,克服了管道無名字的限制,使得無親緣關(guān)系的進(jìn)程同樣可以采用先進(jìn)先出的通信機(jī)制進(jìn)行通信。
管道和FIFO的數(shù)據(jù)是字節(jié)流,應(yīng)用程序之間必須事先確定特定的傳輸"協(xié)議",采用傳播具有特定意義的消息。
要靈活應(yīng)用管道及FIFO,理解它們的讀寫規(guī)則是關(guān)鍵。
附1:kill -l 的運行結(jié)果,顯示了當(dāng)前系統(tǒng)支持的所有信號:
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 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 32) SIGRTMIN 33) SIGRTMIN+1 34) SIGRTMIN+2 35) SIGRTMIN+3 36) SIGRTMIN+4 37) SIGRTMIN+5 38) SIGRTMIN+6 39) SIGRTMIN+7 40) SIGRTMIN+8 41) SIGRTMIN+9 42) SIGRTMIN+10 43) SIGRTMIN+11 44) SIGRTMIN+12 45) SIGRTMIN+13 46) SIGRTMIN+14 47) SIGRTMIN+15 48) SIGRTMAX-15 49) SIGRTMAX-14 50) SIGRTMAX-13 51) SIGRTMAX-12 52) SIGRTMAX-11 53) SIGRTMAX-10 54) SIGRTMAX-9 55) SIGRTMAX-8 56) SIGRTMAX-7 57) SIGRTMAX-6 58) SIGRTMAX-5 59) SIGRTMAX-4 60) SIGRTMAX-3 61) SIGRTMAX-2 62) SIGRTMAX-1 63) SIGRTMAX
除了在此處用來說明管道應(yīng)用外,接下來的專題還要對這些信號分類討論。
附2:對FIFO打開規(guī)則的驗證(主要驗證寫打開對讀打開的依賴性)
#include #include #include #include #define FIFO_SERVER "/tmp/fifoserver" int handle_client(char*); main(int argc,char** argv) { int r_rd; int w_fd; pid_t pid; if((mkfifo(FIFO_SERVER,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST)) printf("cannot create fifoservern"); handle_client(FIFO_SERVER); } int handle_client(char* arg) { int ret; ret=w_open(arg); switch(ret) { case 0: { printf("open %s errorn",arg); printf("no process has the fifo open for readingn"); return -1; } case -1: { printf("something wrong with open the fifo except for ENXIO"); return -1; } case 1: { printf("open server okn"); return 1; } default: { printf("w_no_r return ????n"); return 0; } } unlink(FIFO_SERVER); } int w_open(char*arg) //0 open error for no reading //-1 open error for other reasons //1 open ok { if(open(arg,O_WRONLY|O_NONBLOCK,0)==-1) { if(errno==ENXIO) { return 0; } else return -1; } return 1; }
參考文獻(xiàn):
Unix網(wǎng)絡(luò)編程第二卷:進(jìn)程間通信,作者:W.Richard Stevens,譯者:楊繼張,清華大學(xué)出版社。豐富的Unix進(jìn)程間通信實例及分析,對Linux環(huán)境下的程序開發(fā)有極大的啟發(fā)意義。
Linux內(nèi)核源代碼情景分析(上、下),毛德操、胡希明著,浙江大學(xué)出版社,當(dāng)要驗證某個結(jié)論、想法時,最好的參考資料。
Unix環(huán)境高級編程,作者:W.Richard Stevens,譯者:尤晉元等,機(jī)械工業(yè)出版社。具有豐富的編程實例,以及關(guān)鍵函數(shù)伴隨Unix的發(fā)展歷程。
http://www.linux.org.tw/CLDP/gb/Secure-Programs-HOWTO/x346.html 點明Linux下sigaction的實現(xiàn)基礎(chǔ),Linux源碼../kernel/signal.c更說明了問題。
pipe手冊,最直接而可靠的參考資料。
fifo手冊,最直接而可靠的參考資料。