生活随笔
收集整理的這篇文章主要介紹了
linux编程之pipe()函数
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
管道是一種把兩個進程之間的標準輸入和標準輸出連接起來的機制,從而提供一種讓多個進程間通信的方法,當進程創(chuàng)建管道時,每次
都需要提供兩個文件描述符來操作管道。其中一個對管道進行寫操作,另一個對管道進行讀操作。對管道的讀寫與一般的IO系統(tǒng)函數(shù)一
致,使用write()函數(shù)寫入數(shù)據(jù),使用read()讀出數(shù)據(jù)。
#include<unistd.h>
int pipe(int filedes[2]);
返回值:成功,返回0,否則返回-1。參數(shù)數(shù)組包含pipe使用的兩個文件的描述符。fd[0]:讀管道,fd[1]:寫管道。
必須在fork()中調(diào)用pipe(),否則子進程不會繼承文件描述符。兩個進程不共享祖先進程,就不能使用pipe。但是可以使用命名管道。
?
當管道進行寫入操作的時候,如果寫入的數(shù)據(jù)小于128K則是非原子的,如果大于128K字節(jié),緩沖區(qū)的數(shù)據(jù)將被連續(xù)地寫入
管道,直到全部數(shù)據(jù)寫完為止,如果沒有進程讀取數(shù)據(jù),則將一直阻塞,如下:
在上例程序中,子進程一次性寫入128K數(shù)據(jù),當父進程將全部數(shù)據(jù)讀取完畢的時候,子進程的write()函數(shù)才結束阻塞并且
返回寫入信息。
命名管道FIFO
管道最大的劣勢就是沒有名字,只能用于有一個共同祖先進程的各個進程之間。FIFO代表先進先出,單它是一個單向數(shù)據(jù)流,也就是半雙工,和
管道不同的是:每個FIFO都有一個路徑與之關聯(lián),從而允許無親緣關系的進程訪問。 ?
? ? ? ? #include <sys/types.h>
? ? ? ? #include <sys/stat.h>
? ? ? int mkfifo(const char *pathname, mode_t mode); ? ? ?這里pathname是路徑名,mode是sys/stat.h里面定義的創(chuàng)建文件的權限.
以下示例程序來自:http://blog.chinaunix.net/uid-20498361-id-1940238.html
? 有親緣關系進程間的fifo的例子 ?
/* ?* 有親緣關系的進程間的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)建它,若存在則不算是錯誤, ????// 若想修改其屬性需要先打開得到fd,然后用fcntl來獲取屬性,然后設置屬性. ????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管道并沒有被刪除,必須手動調(diào)用函數(shù)unlink或remove刪除. ????return?0;???? } ?
從例子上可以看出使用fifo時需要注意: *fifo管道是先調(diào)用mkfifo創(chuàng)建,然后再用open打開得到fd來使用. *在打開fifo時要注意,它是半雙工的的,一般不能使用O_RDWR打開,而只能用只讀或只寫打開. ? ?fifo可以用在非親緣關系的進程間,而它的真正用途是在服務器和客戶端之間. 由于它是半雙工的所以,如果要進行客戶端和服務器雙方的通信的話,
每個方向都必須建立兩個管道,一個用于讀,一個用于寫. 下面是一個服務器,對多個客戶端的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ī)則, 若從一個空管道或fifo讀,?
???? * 而在讀之前管道或fifo有打開來寫的操作, 那么讀操作將會阻塞? ???? * 直到管道或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有打開來寫的操作,所以當管道沒有數(shù)據(jù)時,?
????? * read會阻塞,而不是返回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); }
?
總結
以上是生活随笔 為你收集整理的linux编程之pipe()函数 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。