生活随笔
收集整理的這篇文章主要介紹了
linux编程之pipe()函数
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
管道是一種把兩個(gè)進(jìn)程之間的標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出連接起來的機(jī)制,從而提供一種讓多個(gè)進(jìn)程間通信的方法,當(dāng)進(jìn)程創(chuàng)建管道時(shí),每次
都需要提供兩個(gè)文件描述符來操作管道。其中一個(gè)對(duì)管道進(jìn)行寫操作,另一個(gè)對(duì)管道進(jìn)行讀操作。對(duì)管道的讀寫與一般的IO系統(tǒng)函數(shù)一
致,使用write()函數(shù)寫入數(shù)據(jù),使用read()讀出數(shù)據(jù)。
#include<unistd.h>
int pipe(int filedes[2]);
返回值:成功,返回0,否則返回-1。參數(shù)數(shù)組包含pipe使用的兩個(gè)文件的描述符。fd[0]:讀管道,fd[1]:寫管道。
必須在fork()中調(diào)用pipe(),否則子進(jìn)程不會(huì)繼承文件描述符。兩個(gè)進(jìn)程不共享祖先進(jìn)程,就不能使用pipe。但是可以使用命名管道。
?
當(dāng)管道進(jìn)行寫入操作的時(shí)候,如果寫入的數(shù)據(jù)小于128K則是非原子的,如果大于128K字節(jié),緩沖區(qū)的數(shù)據(jù)將被連續(xù)地寫入
管道,直到全部數(shù)據(jù)寫完為止,如果沒有進(jìn)程讀取數(shù)據(jù),則將一直阻塞,如下:
在上例程序中,子進(jìn)程一次性寫入128K數(shù)據(jù),當(dāng)父進(jìn)程將全部數(shù)據(jù)讀取完畢的時(shí)候,子進(jìn)程的write()函數(shù)才結(jié)束阻塞并且
返回寫入信息。
命名管道FIFO
管道最大的劣勢就是沒有名字,只能用于有一個(gè)共同祖先進(jìn)程的各個(gè)進(jìn)程之間。FIFO代表先進(jìn)先出,單它是一個(gè)單向數(shù)據(jù)流,也就是半雙工,和
管道不同的是:每個(gè)FIFO都有一個(gè)路徑與之關(guān)聯(lián),從而允許無親緣關(guān)系的進(jìn)程訪問。 ?
? ? ? ? #include <sys/types.h>
? ? ? ? #include <sys/stat.h>
? ? ? int mkfifo(const char *pathname, mode_t mode); ? ? ?這里pathname是路徑名,mode是sys/stat.h里面定義的創(chuàng)建文件的權(quán)限.
以下示例程序來自:http://blog.chinaunix.net/uid-20498361-id-1940238.html
? 有親緣關(guān)系進(jìn)程間的fifo的例子 ?
/* ?* 有親緣關(guān)系的進(jìn)程間的fifo的使用 ?* fifo 使用的簡單例子 ?*/ #include?"../all.h" #define?FIFO_PATH?"/tmp/hover_fifo" void? do_sig(int?signo) { ????if?(signo?==?SIGCHLD) ????????while?(waitpid(-1,?NULL,?WNOHANG)?>?0) ????????????; }
int main(void) { ????int?ret; ????int?fdr,?fdw; ????pid_t?pid; ????char?words[10]?=?"123456789"; ????char?buf[10]?=?{'\0'};???? ???? ????// 創(chuàng)建它,若存在則不算是錯(cuò)誤, ????// 若想修改其屬性需要先打開得到fd,然后用fcntl來獲取屬性,然后設(shè)置屬性. ????if?(((ret?=?mkfifo(FIFO_PATH,?FILE_MODE))?==?-1)?
???????????????????? &&?(errno?!=?EEXIST)) ????????perr_exit("mkfifo()"); ????fprintf(stderr,?"fifo : %s created successfully!\n",?FIFO_PATH); ????signal(SIGCHLD,?do_sig); ????pid?=?fork(); ????if?(pid?==?0)?{?// child ????????if?((fdr?=?open(FIFO_PATH,?O_WRONLY))?<?0)?// 打開fifo用來寫 ????????????perr_exit("open()"); ????????sleep(2);
??????? // 寫入數(shù)據(jù) ????????if?(write(fdr,?words,?sizeof(words))?!=?sizeof(words))? ????????????perr_exit("write"); ????????fprintf(stderr,?"child write : %s\n",?words); ????????close(fdw); ????}?else?if?(pid?>?0)?{?// parent ????????if?((fdr?=?open(FIFO_PATH,?O_RDONLY))?<?0)?// 打開fifo用來讀 ????????????perr_exit("open()"); ????????fprintf(stderr,?"I father read, waiting for child ...\n"); ????????if?(read(fdr,?buf,?9)?!=?9)?//讀數(shù)據(jù) ????????????perr_exit("read"); ????????fprintf(stderr,?"father get buf : %s\n",?buf); ????????close(fdr); ????} ????// 到這里fifo管道并沒有被刪除,必須手動(dòng)調(diào)用函數(shù)unlink或remove刪除. ????return?0;???? } ?
從例子上可以看出使用fifo時(shí)需要注意: *fifo管道是先調(diào)用mkfifo創(chuàng)建,然后再用open打開得到fd來使用. *在打開fifo時(shí)要注意,它是半雙工的的,一般不能使用O_RDWR打開,而只能用只讀或只寫打開. ? ?fifo可以用在非親緣關(guān)系的進(jìn)程間,而它的真正用途是在服務(wù)器和客戶端之間. 由于它是半雙工的所以,如果要進(jìn)行客戶端和服務(wù)器雙方的通信的話,
每個(gè)方向都必須建立兩個(gè)管道,一個(gè)用于讀,一個(gè)用于寫. 下面是一個(gè)服務(wù)器,對(duì)多個(gè)客戶端的fifo的例子: server 端的例子: ?
/* ?* FIFO server ?*/ #include?"all.h" int main(void) { ????int?fdw,?fdw2; ????int?fdr; ????char?clt_path[PATH_LEN]?=?{'\0'}; ????char?buf[MAX_LINE]?=?{'\0'}; ????char?*p; ????int?n; ???? ????if?(mkfifo(FIFO_SVR,?FILE_MODE)?==?-1?&&?errno?!=?EEXIST)???? ????????perr_exit("mkfifo()");???? ????if?((fdr?=?open(FIFO_SVR,?O_RDONLY))?<?0)???? ????????perr_exit("open()"); ????/*? ???? * 根據(jù)fifo的創(chuàng)建規(guī)則, 若從一個(gè)空管道或fifo讀,?
???? * 而在讀之前管道或fifo有打開來寫的操作, 那么讀操作將會(huì)阻塞? ???? * 直到管道或fifo不打開來讀, 或管道或fifo中有數(shù)據(jù)為止.?
???? *
???? * 這里,我們的fifo本來是打開用來讀的,但是為了,read不返回0,
???? * 讓每次client端讀完都阻塞在fifo上,我們又打開一次來讀. ???? * 見unpv2 charper 4.7 ???? */ ????if?((fdw2?=?open(FIFO_SVR,?O_WRONLY))?<?0)???? ????????fprintf(stderr,?"open()"); ???? ????while?(1)?{ ????????/* read client fifo path from FIFO_SVR */
???? /* 這里由于FIFO_SVR有打開來寫的操作,所以當(dāng)管道沒有數(shù)據(jù)時(shí),?
????? * read會(huì)阻塞,而不是返回0.?
????? */ ????????if?(read(fdr,?clt_path,?PATH_LEN)?<?0)?{ ????????????fprintf(stderr,?"read fifo client path error : %s\n",?strerror(errno));???? ????????????break; ????????} ????????if?((p?=?strstr(clt_path,?"\r\n"))?==?NULL)?{ ????????????fprintf(stderr,?"clt_path error: %s\n",?clt_path); ????????????break; ????????} ????????*p?=?'\0'; ????????DBG("clt_path",?clt_path); ????????if?(access(clt_path,?W_OK)?==?-1)?{?// client fifo ok, but no permission ????????????perror("access()");???? ????????????continue; ????????} ????????/* open client fifo for write */ ????????if?((fdw?=?open(clt_path,?O_WRONLY))?<?0)?{ ????????????perror("open()");???? ????????????continue; ????????} ????????if?((n?=?read(fdr,?buf,?WORDS_LEN))?>?0)?{?/* read server words is ok */ ????????????printf("server read words : %s\n",?buf); ????????????buf[n]?=?'\0'; ????????????write(fdw,?buf,?strlen(buf));???? ????????} ????} ???? ????close(fdw);???? ????unlink(FIFO_SVR); ????exit(0); }
客戶端的例子: ?
?
/* ?* Fifo client ?* ?*/ #include?"all.h" int main(void) { ????int?fdr,?fdw; ????pid_t?pid;???? ????char?clt_path[PATH_LEN]?=?{'\0'}; ????char?buf[MAX_LINE]?=?{'\0'}; ????char?buf_path[MAX_LINE]?=?{'\0'}; ???? ????snprintf(clt_path,?PATH_LEN,?FIFO_CLT_FMT,?(long)getpid());???????? ????DBG("clt_path1 = ",?clt_path); ????snprintf(buf_path,?PATH_LEN,?"%s\r\n",?clt_path); ????if?(mkfifo(clt_path,?FILE_MODE)?==?-1?&&?errno?!=?EEXIST)???? ????????perr_exit("mkfifo()"); ????/* client open clt_path for read ???? * open server for write? ?????? */ ????if?((fdw?=?open(FIFO_SVR,?O_WRONLY))?<?0)? ????????perr_exit("open()"); ???? ????/* write my fifo path to server */???? ????if?(write(fdw,?buf_path,?PATH_LEN)?!=?PATH_LEN)???????? ????????perr_exit("write()"); ????if?(write(fdw,?WORDS,?WORDS_LEN)?<?0)????/* write words to fifo server */ ????????perr_exit("error"); ????if?((fdr?=?open(clt_path,?O_RDONLY))?<?0)???? ????????perr_exit("open()"); ????if?(read(fdr,?buf,?WORDS_LEN)?>?0)?{?????/* read reply from fifo server */ ????????buf[WORDS_LEN]?=?'\0'; ????????printf("server said : %s\n",?buf); ????} ???? ????close(fdr); ????unlink(clt_path); ???? ????exit(0); }
?
總結(jié)
以上是生活随笔 為你收集整理的linux编程之pipe()函数 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。