?? 11.html
字號:
FILE*pipein_fp,*pipeout_fp;<br>charreadbuf[80];<br>/*Createonewaypipelinewithcalltopopen()*/<br>if((pipein_fp=popen("ls","r"))==NULL)<br>{<br>perror("popen");<br>exit(1);<br>}<br>/*Createonewaypipelinewithcalltopopen()*/<br>if((pipeout_fp=popen("sort","w"))==NULL)<br>{<br>perror("popen");<br>exit(1);<br>}<br>/*Processingloop*/<br>while(fgets(readbuf,80,pipein_fp))<br>fputs(readbuf,pipeout_fp);<br>/*Closethepipes*/<br>pclose(pipein_fp);<br>pclose(pipeout_fp);<br>return(0);<br>}<br>最后,我們再看一個使用popen()的例子。此程序用于創(chuàng)建一個命令和文件之間的管道:<br>#include<stdio.h><br>intmain(intargc,char*argv[])<br>{<br>FILE*pipe_fp,*infile;<br>charreadbuf[80];<br>if(argc!=3){<br>fprintf(stderr,"USAGE:popen3[command][filename]\n");<br>exit(1);<br>}<br>/*Open up input file*/<br>if((infile=fopen(argv[2],"rt"))==NULL)<br>{<br>perror("fopen");<br>exit(1);<br>}<br>/*Create one way pipe line with call topopen()*/<br>if((pipe_fp=popen(argv[1],"w"))==NULL)<br>{<br>perror("popen");<br>exit(1);<br>}<br>/*Processingloop*/<br>do{<br>fgets(readbuf,80,infile);<br>if(feof(infile))break;<br>fputs(readbuf,pipe_fp);<br>}while(!feof(infile));<br>fclose(infile);<br>pclose(pipe_fp);<br>return(0);<br>}<br>下面是使用此程序的例子:<br>popen3sortpopen3.c<br>popen3catpopen3.c<br>popen3morepopen3.c<br>popen3catpopen3.c|grepmain<p><p><p><center><A HREF="#Content">[目錄]</A></center><hr><br><A NAME="I242" ID="I242"></A><center><b><font size=+2>命名管道</font></b></center><br> 命名管道和一般的管道基本相同,但也有一些顯著的不同:<p>*命名管道是在文件系統(tǒng)中作為一個特殊的設(shè)備文件而存在的。<br>*不同祖先的進(jìn)程之間可以通過管道共享數(shù)據(jù)。<br>*當(dāng)共享管道的進(jìn)程執(zhí)行完所有的I/O操作以后,命名管道將繼續(xù)保存在文件系統(tǒng)中以便以后使用。<p> 一個管道必須既有讀取進(jìn)程,也要有寫入進(jìn)程。如果一個進(jìn)程試圖寫入到一個沒有讀取進(jìn)程的管道中,那么系統(tǒng)內(nèi)核將會產(chǎn)生SIGPIPE信號。當(dāng)兩個以上的進(jìn)程同時使用管道時,這一點尤其重要。<p><center><A HREF="#Content">[目錄]</A></center><hr><br><A NAME="I243" ID="I243"></A><center><b><font size=+2>創(chuàng)建FIFO</font></b></center><br> 可以有幾種方法創(chuàng)建一個命名管道。頭兩種方法可以使用shell。<p>mknodMYFIFOp<br>mkfifoa=rwMYFIFO<br> 上面的兩個命名執(zhí)行同樣的操作,但其中有一點不同。命令mkfifo提供一個在創(chuàng)建之后直接改變FIFO文件存取權(quán)限的途徑,而命令mknod需要調(diào)用命令chmod。<br> 一個物理文件系統(tǒng)可以通過p指示器十分容易地分辨出一個FIFO文件。<p>$ls-lMYFIFO<br>prw-r--r--1rootroot0Dec1422:15MYFIFO|<p> 請注意在文件名后面的管道符號“|”。<br> 我們可以使用系統(tǒng)調(diào)用mknod()來創(chuàng)建一個FIFO管道:<p>庫函數(shù):mknod();<br>原型:intmknod(char*pathname,mode_tmode,dev_tdev);<br>返回值:如果成功,返回0<br>如果失敗,返回-1:errno=EFAULT(無效路徑名)<br>EACCES(無存取權(quán)限)<br>ENAMETOOLONG(路徑名太長)<br>ENOENT(無效路徑名)<br>ENOTDIR(無效路徑名)<p> 下面看一個使用C語言創(chuàng)建FIFO管道的例子:<p>mknod("/tmp/MYFIFO",S_IFIFO|0666,0);<p> 在這個例子中,文件/tmp/MYFIFO是要創(chuàng)建的FIFO文件。它的存取權(quán)限是0666。存取權(quán)限<br>也可以使用umask修改:<p>final_umask=requested_permissions&~original_umask<p> 一個常用的使用系統(tǒng)調(diào)用umask()的方法就是臨時地清除umask的值:<br>umask(0);<br>mknod("/tmp/MYFIFO",S_IFIFO|0666,0);<p> 另外,mknod()中的第三個參數(shù)只有在創(chuàng)建一個設(shè)備文件時才能用到。它包括設(shè)備文件的<br>主設(shè)備號和從設(shè)備號。<br>}<br>}<p><p><p><br><center><A HREF="#Content">[目錄]</A></center><hr><br><A NAME="I244" ID="I244"></A><center><b><font size=+2>操作FIFO</font></b></center><br> FIFO上的I/O操作和正常管道上的I/O操作基本一樣,只有一個主要的不同。系統(tǒng)調(diào)用open用來在物理上打開一個管道。在半雙工的管道中,這是不必要的。因為管道在系統(tǒng)內(nèi)核中,而不是在一個物理的文件系統(tǒng)中。在我們的例子中,我們將像使用一個文件流一樣使用管道,也就是使用fopen()打開管道,使用fclose()關(guān)閉它。<br> 請看下面的簡單的服務(wù)程序進(jìn)程:<br>#include<stdio.h><br>#include<stdlib.h><br>#include<sys/stat.h><br>#include<unistd.h><br>#include<linux/stat.h><br>#defineFIFO_FILE"MYFIFO"<br>intmain(void)<br>{<br>FILE*fp;<br>charreadbuf[80];<br>/*CreatetheFIFOifitdoesnotexist*/<br>umask(0);<br>mknod(FIFO_FILE,S_IFIFO|0666,0);<br>while(1)<br>{<br>fp=fopen(FIFO_FILE,"r");<br>fgets(readbuf,80,fp);<br>printf("Receivedstring:%s\n",readbuf);<br>fclose(fp);<br>return(0);<br> 因為FIFO管道缺省時有阻塞的函數(shù),所以你可以在后臺運行此程序:<br>$fifoserver&<br> 再來看一下下面的簡單的客戶端程序:<br>#include<stdio.h><br>#include<stdlib.h><br>#defineFIFO_FILE"MYFIFO"<br>intmain(int argc,char* argv[])<br>{<br>FILE*fp;<br>if(argc!=2){<br>printf("USAGE:fifoclient[string]\n");<br>exit(1);<br>}<br>if((fp=fopen(FIFO_FILE,"w"))==NULL){<br>perror("fopen");<br>exit(1);<br>}<br>fputs(argv[1],fp);<br>fclose(fp);<br>return(0);<br>}<p><p><center><A HREF="#Content">[目錄]</A></center><hr><br><A NAME="I245" ID="I245"></A><center><b><font size=+2>阻塞FIFO</font></b></center><br> 一般情況下,F(xiàn)IFO管道上將會有阻塞的情況發(fā)生。也就是說,如果一個FIFO管道打開供讀取的話,它將一直阻塞,直到其他的進(jìn)程打開管道寫入信息。這種過程反過來也一樣。如果你不需要阻塞函數(shù)的話,你可以在系統(tǒng)調(diào)用open()中設(shè)置O_NONBLOCK標(biāo)志,這樣可以取消缺省的阻塞函數(shù)。<p><p><p><center><A HREF="#Content">[目錄]</A></center><hr><br><A NAME="I246" ID="I246"></A><center><b><font size=+2>消息隊列</font></b></center><br> 在UNIX的SystemV版本,AT&T引進(jìn)了三種新形式的IPC功能(消息隊列、信號量、以及共享內(nèi)存)。但BSD版本的UNIX使用套接口作為主要的IPC形式。Linux系統(tǒng)同時支持這兩個版本。<br><center><A HREF="#Content">[目錄]</A></center><hr><br><A NAME="I247" ID="I247"></A><center><b><font size=+2>msgget()</font></b></center><br>系統(tǒng)調(diào)用msgget()<p> 如果希望創(chuàng)建一個新的消息隊列,或者希望存取一個已經(jīng)存在的消息隊列,你可以使用系統(tǒng)調(diào)用msgget()。<p>系統(tǒng)調(diào)用:msgget();<br>原型:intmsgget(key_t key,int msgflg);<br>返回值:如果成功,返回消息隊列標(biāo)識符<br>如果失敗,則返回-1:errno=EACCESS(權(quán)限不允許)<br>EEXIST(隊列已經(jīng)存在,無法創(chuàng)建)<br>EIDRM(隊列標(biāo)志為刪除)<br>ENOENT(隊列不存在)<br>ENOMEM(創(chuàng)建隊列時內(nèi)存不夠)<br>ENOSPC(超出最大隊列限制)<p> 系統(tǒng)調(diào)用msgget()中的第一個參數(shù)是關(guān)鍵字值(通常是由ftok()返回的)。然后此關(guān)鍵字值將會和其他已經(jīng)存在于系統(tǒng)內(nèi)核中的關(guān)鍵字值比較。這時,打開和存取操作是和參數(shù)msgflg中的內(nèi)容相關(guān)的。<br>IPC_CREAT如果內(nèi)核中沒有此隊列,則創(chuàng)建它。<br>IPC_EXCL當(dāng)和IPC_CREAT一起使用時,如果隊列已經(jīng)存在,則失敗。<p> 如果單獨使用IPC_CREAT,則msgget()要么返回一個新創(chuàng)建的消息隊列的標(biāo)識符,要么返回具有相同關(guān)鍵字值的隊列的標(biāo)識符。如果IPC_EXCL和IPC_CREAT一起使用,則msgget()要么創(chuàng)建一個新的消息隊列,要么如果隊列已經(jīng)存在則返回一個失敗值-1。IPC_EXCL單獨使用是沒有用處的。<br>下面看一個打開和創(chuàng)建一個消息隊列的例子:<br>intopen_queue(key_t keyval)<br>{<br>intqid;<br>if((qid=msgget(keyval,IPC_CREAT|0660))==-1)<br>{<br>return(-1);<br>}<br>return(qid);<br>}<p><p><p><center><A HREF="#Content">[目錄]</A></center><hr><br><A NAME="I248" ID="I248"></A><center><b><font size=+2>msgsnd()</font></b></center><br>系統(tǒng)調(diào)用msgsnd()<p> 一旦我們得到了隊列標(biāo)識符,我們就可以在隊列上執(zhí)行我們希望的操作了。如果想要往隊列中發(fā)送一條消息,你可以使用系統(tǒng)調(diào)用msgsnd():<p>系統(tǒng)調(diào)用:msgsnd();<br>原型:intmsgsnd(int msqid,struct msgbuf*msgp,int msgsz,int msgflg);<br>返回值:如果成功,0。<br>如果失敗,-1:errno=EAGAIN(隊列已滿,并且使用了IPC_NOWAIT)<br>EACCES(沒有寫的權(quán)限)<br>EFAULT(msgp地址無效)<br>EIDRM(消息隊列已經(jīng)刪除)<br>EINTR(當(dāng)?shù)却龑懖僮鲿r,收到一個信號)<br>EINVAL(無效的消息隊列標(biāo)識符,非正數(shù)的消息類型,或<br>者無效的消息長度)<br>ENOMEM(沒有足夠的內(nèi)存復(fù)制消息緩沖區(qū))<p> 系統(tǒng)調(diào)用msgsnd()的第一個參數(shù)是消息隊列標(biāo)識符,它是由系統(tǒng)調(diào)用msgget返回的。第二個參數(shù)是msgp,是指向消息緩沖區(qū)的指針。參數(shù)msgsz中包含的是消息的字節(jié)大小,但不包括消息類型的長度(4個字節(jié))。<br> 參數(shù)msgflg可以設(shè)置為0(此時為忽略此參數(shù)),或者使用IPC_NOWAIT。<p> 如果消息隊列已滿,那么此消息則不會寫入到消息隊列中,控制將返回到調(diào)用進(jìn)程中。如果沒有指明,調(diào)用進(jìn)程將會掛起,直到消息可以寫入到隊列中。<br> 下面是一個發(fā)送消息的程序:<p>intsend_message(int qid,struct mymsgbuf *qbuf)<br>{<br>intresult,length;<br>/*The length is essentially the size of the structure minus sizeof(mtype)*/<br>length=sizeof(structmymsgbuf)-sizeof(long);<br>if((result=msgsnd(qid,qbuf,length,0))==-1)<br>{<br>return(-1);<br>}<br>return(result);<br>}<p> 這個小程序試圖將存儲在緩沖區(qū)qbuf中的消息發(fā)送到消息隊列qid中。下面的程序是結(jié)合了上面兩個程序的一個完整程序:<p>#include<stdio.h><br>#include<stdlib.h><br>#include<linux/ipc.h><br>#include<linux/msg.h><br>main()<br>{<br>intqid;<br>key_t msgkey;<br>struct mymsgbuf{<br>longmtype;/*Message type*/<br>intrequest;/*Work request number*/<br>doublesalary;/*Employee's salary*/<br>}msg;<br>/*Generateour IPC key value*/<br>msgkey=ftok(".",'m');<br>/*Open/createthequeue*/<br>if((qid=open_queue(msgkey))==-1){<br>perror("open_queue");<br>exit(1);<br>}<br>/*Load up the message with a r bitrary test data*/<br>msg.mtype=1;/*Messagetypemustbeapositivenumber!*/<br>msg.request=1;/*Dataelement#1*/<br>msg.salary=1000.00;/*Data element #2(my yearly salary!)*/<br>/*Bombsaway!*/<br>
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -