1、管道概述及相關API應用

1.1管道相關的關鍵概念

亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

linuxIPC——管道

系統 1825 0
<p><span style="font-size: medium;"><a name="N1003C"><span class="atitle">1、 管道概述及相關API應用</span>
</a>
</span>
</p>
<p><span style="font-size: medium;"><a name="N10042"><span class="smalltitle">1.1 管道相關的關鍵概念</span>
</a>
</span>
</p>
<p><span style="font-size: medium;">管道是Linux支持的最初Unix IPC形式之一,具有以下特點:</span>
</p>
<ul>
<li>
<span style="font-size: medium;">管道是半雙工的,數據只能向一個方向流動;需要雙方通信時,需要建立起兩個管道;</span>
</li>
<li>
<span style="font-size: medium;">只能用于父子進程或者兄弟進程之間(具有親緣關系的進程);</span>
</li>
<li>
<span style="font-size: medium;">單獨構成一種獨立的文件系統:管道對于管道兩端的進程而言,就是一個文件,但它不是普通的文件,它不屬于某種文件系統,而是自立門戶,單獨構成一種文件系統,并且只存在與內存中。</span>
</li>
<li>
<span style="font-size: medium;">數據的讀出和寫入:一個進程向管道中寫的內容被管道另一端的進程讀出。寫入的內容每次都添加在管道緩沖區的末尾,并且每次都是從緩沖區的頭部讀出數據。</span>
</li>
</ul>
<p><span style="font-size: medium;"><a name="N1005A"><span class="smalltitle">1.2管道的創建:</span>
</a>
</span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;">#include &lt;unistd.h&gt;
int pipe(int fd[2])
</span>

</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<p><span style="font-size: medium;">該函數創建的管道的兩端處于一個進程中間,在實際應用中沒有太大意義,因此,一個進程在由pipe()創建管道后,一般再fork一個
子進程,然后通過管道實現父子進程間的通信(因此也不難推出,只要兩個進程中存在親緣關系,這里的親緣關系指的是具有共同的祖先,都可以采用管道方式來進
行通信)。</span>
</p>
<p><span style="font-size: medium;"><a name="N10067"><span class="smalltitle">1.3管道的讀寫規則:</span>
</a>
</span>
</p>
<p><span style="font-size: medium;">管道兩端可分別用描述字fd[0]以及fd[1]來描述,需要注意的是,管道的兩端是固定了任務的。即一端只能用于讀,由描述字
fd[0]表示,稱其為管道讀端;另一端則只能用于寫,由描述字fd[1]來表示,稱其為管道寫端。如果試圖從管道寫端讀取數據,或者向管道讀端寫入數據
都將導致錯誤發生。一般文件的I/O函數都可以用于管道,如close、read、write等等。</span>
</p>
<p><span style="font-size: medium;">從管道中讀取數據:</span>
</p>
<ul>
<li>
<span style="font-size: medium;">如果管道的寫端不存在,則認為已經讀到了數據的末尾,讀函數返回的讀出字節數為0;</span>
</li>
<li>
<span style="font-size: medium;">當管道的寫端存在時,如果請求的字節數目大于PIPE_BUF,則返回管道中現有的數據字節數,如果請求的字節數目不大于
PIPE_BUF,則返回管道中現有數據字節數(此時,管道中數據量小于請求的數據量);或者返回請求的字節數(此時,管道中數據量不小于請求的數據
量)。注:(PIPE_BUF在include/linux/limits.h中定義,不同的內核版本可能會有所不同。Posix.1要求
PIPE_BUF至少為512字節,red hat 7.2中為4096)。</span>
</li>
</ul>
<p><span style="font-size: medium;">關于管道的讀規則驗證:</span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;"> /**************
* readtest.c *
**************/
#include &lt;unistd.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;errno.h&gt;
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)&lt;0)
{
printf("pipe create error/n");
return -1;
}

if((pid=fork())==0)
{
printf("/n");
close(pipe_fd[1]);
sleep(3);//確保父進程關閉寫端
??? r_num=read(pipe_fd[0],r_buf,100);
printf( "read num is %d?? the data read from the pipe is %d/n",r_num,atoi(r_buf));

close(pipe_fd[0]);
exit();
}
else if(pid&gt;0)
{
close(pipe_fd[0]);//read
strcpy(w_buf,"111");
if(write(pipe_fd[1],w_buf,4)!=-1)
printf("parent write over/n");
close(pipe_fd[1]);//write
printf("parent close fd[1] over/n");
sleep(10);
}
}
/**************************************************
* 程序輸出結果:
* parent write over
* parent close fd[1] over
* read num is 4?? the data read from the pipe is 111
* 附加結論:
* 管道寫端關閉后,寫入的數據將一直存在,直到讀出為止.
****************************************************/
</span>

</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<p><span style="font-size: medium;">向管道中寫入數據:</span>
</p>
<ul>
<li>
<span style="font-size: medium;">向管道中寫入數據時,linux將不保證寫入的原子性,管道緩沖區一有空閑區域,寫進程就會試圖向管道寫入數據。如果讀進程不讀走管道緩沖區中的數據,那么寫操作將一直阻塞。
????????? <br>
注:只有在管道的讀端存在時,向管道中寫入數據才有意義。否則,向管道中寫入數據的進程將收到內核傳來的SIFPIPE信號,應用程序可以處理該信號,也可以忽略(默認動作則是應用程序終止)。
??????? </span>
</li>
</ul>
<p><span style="font-size: medium;">對管道的寫規則的驗證1:寫端對讀端存在的依賴性</span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;">#include &lt;unistd.h&gt;
#include &lt;sys/types.h&gt;
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)&lt;0)
{
printf("pipe create error/n");
return -1;
}

if((pid=fork())==0)
{
close(pipe_fd[0]);
close(pipe_fd[1]);
sleep(10);
exit();
}
else if(pid&gt;0)
{
sleep(1);? //等待子進程完成關閉讀端的操作
close(pipe_fd[0]);//write
w_buf="111";
if((writenum=write(pipe_fd[1],w_buf,4))==-1)
printf("write to pipe error/n");
else
printf("the bytes write to pipe is %d /n", writenum);

close(pipe_fd[1]);
}
}
</span>

</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<p><span style="font-size: medium;">則輸出結果為: Broken
pipe,原因就是該管道以及它的所有fork()產物的讀端都已經被關閉。如果在父進程中保留讀端,即在寫完pipe后,再關閉父進程的讀端,也會正常
寫入pipe,讀者可自己驗證一下該結論。因此,在向管道寫入數據時,至少應該存在某一個進程,其中管道讀端沒有被關閉,否則就會出現上述錯誤(管道斷
裂,進程收到了SIGPIPE信號,默認動作是進程終止)</span>
</p>
<p><span style="font-size: medium;">對管道的寫規則的驗證2:linux不保證寫管道的原子性驗證</span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;">#include &lt;unistd.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;errno.h&gt;
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)&lt;0)
{
printf("pipe create error/n");
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 %d/n",rnum);
}
close(pipe_fd[0]);

exit();
}
else if(pid&gt;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 error/n");
else
printf("the bytes write to pipe is %d /n", writenum);
writenum=write(pipe_fd[1],w_buf,4096);
close(pipe_fd[1]);
}
}
輸出結果:
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
......
</span>

</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<p><span style="font-size: medium;">結論:</span>
</p>
<p><span style="font-size: medium;">寫入數目小于4096時寫入是非原子的!
??????? <br>
如果把父進程中的兩次寫入字節數都改為5000,則很容易得出下面結論:
??????? <br>
寫入管道的數據量大于4096字節時,緩沖區的空閑空間將被寫入數據(補齊),直到寫完所有數據為止,如果沒有進程讀數據,則一直阻塞。
????? </span>
</p>
<p><span style="font-size: medium;"><a name="N100A9"><span class="smalltitle">1.4管道應用實例:</span>
</a>
</span>
</p>
<p>
??????? <span style="font-size: medium;"><strong>實例一:用于shell</strong>
</span>
????? </p>
<p><span style="font-size: medium;">管道可用于輸入輸出重定向,它將一個命令的輸出直接定向到另一個命令的輸入。比如,當在某個shell程序(Bourne
shell或C shell等)鍵入who│wc -l后,相應shell程序將創建who以及wc兩個進程和這兩個進程間的管道。考慮下面的命令行:</span>
</p>
<p><span style="font-size: medium;">$kill -l 運行結果見 。
????? </span>
</p>
<p><span style="font-size: medium;">$kill -l | grep SIGRTMIN 運行結果如下:</span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;">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
</span>

</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<p>
??????? <span style="font-size: medium;"><strong>實例二:用于具有親緣關系的進程間通信</strong>
</span>
????? </p>
<p><span style="font-size: medium;">下面例子給出了管道的具體應用,父進程通過管道發送一些命令給子進程,子進程解析命令,并根據命令作相應處理。</span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;">#include &lt;unistd.h&gt;
#include &lt;sys/types.h&gt;
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)&lt;0)
{
printf("pipe create error/n");
return -1;
}
if((pid=fork())==0)
//子進程:解析從管道中獲取的命令,并作相應的處理
{
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 over/n now child process exit/n");
childexit=1;
}

?????? else if(handle_cmd(cmd)!=0)
return;
sleep(1);
}
close(pipe_fd[0]);
exit();
}
else if(pid&gt;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&lt;4;i++)
write(pipe_fd[1],w_buf[i],4);
close(pipe_fd[1]);
}
}
//下面是子進程的命令處理函數(特定于應用):
int handle_cmd(int cmd)
{
if((cmd&lt;0)||(cmd&gt;256))
//suppose child only support 256 commands
{
printf("child: invalid command /n");
return -1;
}
printf("child: the cmd from parent is %d/n", cmd);
return 0;
}
</span>

</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<p><span style="font-size: medium;"><a name="N100D3"><span class="smalltitle">1.5管道的局限性</span>
</a>
</span>
</p>
<p><span style="font-size: medium;">管道的主要局限性正體現在它的特點上:</span>
</p>
<ul>
<li>
<span style="font-size: medium;">只支持單向數據流;</span>
</li>
<li>
<span style="font-size: medium;">只能用于具有親緣關系的進程之間;</span>
</li>
<li>
<span style="font-size: medium;">沒有名字;</span>
</li>
<li>
<span style="font-size: medium;">管道的緩沖區是有限的(管道制存在于內存中,在管道創建時,為緩沖區分配一個頁面大小);</span>
</li>
<li>
<span style="font-size: medium;">管道所傳送的是無格式字節流,這就要求管道的讀出方和寫入方必須事先約定好數據的格式,比如多少字節算作一個消息(或命令、或記錄)等等;</span>
</li>
</ul>
<div class="ibm-alternate-rule">
<hr>
</div>
<p><span style="font-size: medium;"><a name="N100EE"><span class="atitle">2、 有名管道概述及相關API應用</span>
</a>
</span>
</p>
<p><span style="font-size: medium;"><a name="N100F4"><span class="smalltitle">2.1 有名管道相關的關鍵概念</span>
</a>
</span>
</p>
<p><span style="font-size: medium;">管道應用的一個重大限制是它沒有名字,因此,只能用于具有親緣關系的進程間通信,在有名管道(named
pipe或FIFO)提出后,該限制得到了克服。FIFO不同于管道之處在于它提供一個路徑名與之關聯,以FIFO的文件形式存在于文件系統中。這樣,即
使與FIFO的創建進程不存在親緣關系的進程,只要可以訪問該路徑,就能夠彼此通過FIFO相互通信(能夠訪問該路徑的進程以及FIFO的創建進程之
間),因此,通過FIFO不相關的進程也能交換數據。值得注意的是,FIFO嚴格遵循先進先出(first in first
out),對管道及FIFO的讀總是從開始處返回數據,對它們的寫則把數據添加到末尾。它們不支持諸如lseek()等文件定位操作。</span>
</p>
<p><span style="font-size: medium;"><a name="N100FD"><span class="smalltitle">2.2有名管道的創建</span>
</a>
</span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;">#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
int mkfifo(const char * pathname, mode_t mode)
</span>

</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<p><span style="font-size: medium;">該函數的第一個參數是一個普通的路徑名,也就是創建后FIFO的名字。第二個參數與打開普通文件的open()函數中的mode
參數相同。
如果mkfifo的第一個參數是一個已經存在的路徑名時,會返回EEXIST錯誤,所以一般典型的調用代碼首先會檢查是否返回該錯誤,如果確實返回該錯
誤,那么只要調用打開FIFO的函數就可以了。一般文件的I/O函數都可以用于FIFO,如close、read、write等等。</span>
</p>
<p><span style="font-size: medium;"><a name="N1010A"><span class="smalltitle">2.3有名管道的打開規則</span>
</a>
</span>
</p>
<p><span style="font-size: medium;">有名管道比管道多了一個打開操作:open。</span>
</p>
<p><span style="font-size: medium;">FIFO的打開規則:</span>
</p>
<p><span style="font-size: medium;">如果當前打開操作是為讀而打開FIFO時,若已經有相應進程為寫而打開該FIFO,則當前打開操作將成功返回;否則,可能阻塞直到有相應進程為寫而打開該FIFO(當前打開操作設置了阻塞標志);或者,成功返回(當前打開操作沒有設置阻塞標志)。</span>
</p>
<p><span style="font-size: medium;">如果當前打開操作是為寫而打開FIFO時,如果已經有相應進程為讀而打開該FIFO,則當前打開操作將成功返回;否則,可能阻塞直到有相應進程為讀而打開該FIFO(當前打開操作設置了阻塞標志);或者,返回ENXIO錯誤(當前打開操作沒有設置阻塞標志)。</span>
</p>
<p><span style="font-size: medium;">對打開規則的驗證參見 下面。
????? </span>
</p>
<p><span style="font-size: medium;"><a name="N10123"><span class="smalltitle">2.4有名管道的讀寫規則</span>
</a>
</span>
</p>
<p><span style="font-size: medium;">從FIFO中讀取數據:</span>
</p>
<p><span style="font-size: medium;">約定:如果一個進程為了從FIFO中讀取數據而阻塞打開FIFO,那么稱該進程內的讀操作為設置了阻塞標志的讀操作。</span>
</p>
<ul>
<li>
<span style="font-size: medium;">如果有進程寫打開FIFO,且當前FIFO內沒有數據,則對于設置了阻塞標志的讀操作來說,將一直阻塞。對于沒有設置阻塞標志讀操作來說則返回-1,當前errno值為EAGAIN,提醒以后再試。</span>
</li>
<li>
<span style="font-size: medium;">對于設置了阻塞標志的讀操作說,造成阻塞的原因有兩種:當前FIFO內有數據,但有其它進程在讀這些數據;另外就是FIFO內沒有數據。解阻塞的原因則是FIFO中有新的數據寫入,不論信寫入數據量的大小,也不論讀操作請求多少數據量。</span>
</li>
<li>
<span style="font-size: medium;">讀打開的阻塞標志只對本進程第一個讀操作施加作用,如果本進程內有多個讀操作序列,則在第一個讀操作被喚醒并完成讀操作后,其它將要執行的讀操作將不再阻塞,即使在執行讀操作時,FIFO中沒有數據也一樣(此時,讀操作返回0)。</span>
</li>
<li>
<span style="font-size: medium;">如果沒有進程寫打開FIFO,則設置了阻塞標志的讀操作會阻塞。</span>
</li>
</ul>
<p><span style="font-size: medium;">注:如果FIFO中有數據,則設置了阻塞標志的讀操作不會因為FIFO中的字節數小于請求讀的字節數而阻塞,此時,讀操作會返回FIFO中現有的數據量。</span>
</p>
<p><span style="font-size: medium;">向FIFO中寫入數據:</span>
</p>
<p><span style="font-size: medium;">約定:如果一個進程為了向FIFO中寫入數據而阻塞打開FIFO,那么稱該進程內的寫操作為設置了阻塞標志的寫操作。</span>
</p>
<p><span style="font-size: medium;">對于設置了阻塞標志的寫操作:</span>
</p>
<ul>
<li>
<span style="font-size: medium;">當要寫入的數據量不大于PIPE_BUF時,linux將保證寫入的原子性。如果此時管道空閑緩沖區不足以容納要寫入的字節數,則進入睡眠,直到當緩沖區中能夠容納要寫入的字節數時,才開始進行一次性寫操作。</span>
</li>
<li>
<span style="font-size: medium;">當要寫入的數據量大于PIPE_BUF時,linux將不再保證寫入的原子性。FIFO緩沖區一有空閑區域,寫進程就會試圖向管道寫入數據,寫操作在寫完所有請求寫的數據后返回。</span>
</li>
</ul>
<p><span style="font-size: medium;">對于沒有設置阻塞標志的寫操作:</span>
</p>
<ul>
<li>
<span style="font-size: medium;">當要寫入的數據量大于PIPE_BUF時,linux將不再保證寫入的原子性。在寫滿所有FIFO空閑緩沖區后,寫操作返回。</span>
</li>
<li>
<span style="font-size: medium;">當要寫入的數據量不大于PIPE_BUF時,linux將保證寫入的原子性。如果當前FIFO空閑緩沖區能夠容納請求寫入的字節數,寫完后成功返回;如果當前FIFO空閑緩沖區不能夠容納請求寫入的字節數,則返回EAGAIN錯誤,提醒以后再寫;</span>
</li>
</ul>
<p><span style="font-size: medium;">對FIFO讀寫規則的驗證:</span>
</p>
<p><span style="font-size: medium;">下面提供了兩個對FIFO的讀寫程序,適當調節程序中的很少地方或者程序的命令行參數就可以對各種FIFO讀寫規則進行驗證。</span>
</p>
<p>
????? <span style="font-size: medium;"><br><a name="N10165"><strong>程序1:寫FIFO的程序</strong>
</a>
<br></span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;">#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;errno.h&gt;
#include &lt;fcntl.h&gt;
#define FIFO_SERVER "/tmp/fifoserver"
main(int argc,char** argv)
//參數為即將寫入的字節數
{
int fd;
char w_buf[4096*2];
int real_wnum;
memset(w_buf,0,4096*2);
if((mkfifo(FIFO_SERVER,O_CREAT|O_EXCL)&lt;0)&amp;&amp;(errno!=EEXIST))
printf("cannot create fifoserver/n");
if(fd==-1)
if(errno==ENXIO)
printf("open error; no reading process/n");

???? fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0);
//設置非阻塞標志
//fd=open(FIFO_SERVER,O_WRONLY,0);
//設置阻塞標志
real_wnum=write(fd,w_buf,2048);
if(real_wnum==-1)
{
if(errno==EAGAIN)
printf("write to fifo error; try later/n");
}
else
printf("real write num is %d/n",real_wnum);
real_wnum=write(fd,w_buf,5000);
//5000用于測試寫入字節大于4096時的非原子性
//real_wnum=write(fd,w_buf,4096);
//4096用于測試寫入字節不大于4096時的原子性

if(real_wnum==-1)
if(errno==EAGAIN)
printf("try later/n");
}
</span>

</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br><br><a name="N1016F"><strong>程序2:與程序1一起測試寫FIFO的規則,第一個命令行參數是請求從FIFO讀出的字節數</strong>
</a>
</span>

????? <span style="font-size: medium;"><br></span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;">#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;errno.h&gt;
#include &lt;fcntl.h&gt;
#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 %d/n",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 error/n");
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 avlaible/n");
printf("real read bytes %d/n",ret_size);
sleep(1);
}
pause();
unlink(FIFO_SERVER);
}
</span>

</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<p><span style="font-size: medium;">程序應用說明:</span>
</p>
<p><span style="font-size: medium;">把讀程序編譯成兩個不同版本:</span>
</p>
<ul>
<li>
<span style="font-size: medium;">阻塞讀版本:br</span>
</li>
<li>
<span style="font-size: medium;">以及非阻塞讀版本nbr</span>
</li>
</ul>
<p><span style="font-size: medium;">把寫程序編譯成兩個四個版本:</span>
</p>
<ul>
<li>
<span style="font-size: medium;">非阻塞且請求寫的字節數大于PIPE_BUF版本:nbwg</span>
</li>
<li>
<span style="font-size: medium;">非阻塞且請求寫的字節數不大于PIPE_BUF版本:版本nbw</span>
</li>
<li>
<span style="font-size: medium;">阻塞且請求寫的字節數大于PIPE_BUF版本:bwg</span>
</li>
<li>
<span style="font-size: medium;">阻塞且請求寫的字節數不大于PIPE_BUF版本:版本bw</span>
</li>
</ul>
<p><span style="font-size: medium;">下面將使用br、nbr、w代替相應程序中的阻塞讀、非阻塞讀</span>
</p>
<p><span style="font-size: medium;">驗證阻塞寫操作:</span>
</p>
<ol>
<li>
<span style="font-size: medium;">當請求寫入的數據量大于PIPE_BUF時的非原子性:
????????? </span>

<ul>
<li>
<span style="font-size: medium;">nbr 1000</span>
</li>
<li>
<span style="font-size: medium;">bwg</span>
</li>
</ul>
</li>
<li>
<span style="font-size: medium;">當請求寫入的數據量不大于PIPE_BUF時的原子性:
????????? </span>

<ul>
<li>
<span style="font-size: medium;">nbr 1000</span>
</li>
<li>
<span style="font-size: medium;">bw</span>
</li>
</ul>
</li>
</ol>
<p><span style="font-size: medium;">驗證非阻塞寫操作:</span>
</p>
<ol>
<li>
<span style="font-size: medium;">當請求寫入的數據量大于PIPE_BUF時的非原子性:
????????? </span>

<ul>
<li>
<span style="font-size: medium;">nbr 1000</span>
</li>
<li>
<span style="font-size: medium;">nbwg</span>
</li>
</ul>
</li>
<li>
<span style="font-size: medium;">請求寫入的數據量不大于PIPE_BUF時的原子性:
????????? </span>

<ul>
<li>
<span style="font-size: medium;">nbr 1000</span>
</li>
<li>
<span style="font-size: medium;">nbw</span>
</li>
</ul>
</li>
</ol>
<p><span style="font-size: medium;">不管寫打開的阻塞標志是否設置,在請求寫入的字節數大于4096時,都不保證寫入的原子性。但二者有本質區別:</span>
</p>
<p><span style="font-size: medium;">對于阻塞寫來說,寫操作在寫滿FIFO的空閑區域后,會一直等待,直到寫完所有數據為止,請求寫入的數據最終都會寫入FIFO;</span>
</p>
<p><span style="font-size: medium;">而非阻塞寫則在寫滿FIFO的空閑區域后,就返回(實際寫入的字節數),所以有些數據最終不能夠寫入。</span>
</p>
<p><span style="font-size: medium;">對于讀操作的驗證則比較簡單,不再討論。</span>
</p>
<p><span style="font-size: medium;"><a name="N101E5"><span class="smalltitle">2.5有名管道應用實例</span>
</a>
</span>
</p>
<p><span style="font-size: medium;">在驗證了相應的讀寫規則后,應用實例似乎就沒有必要了。</span>
</p>
<div class="ibm-alternate-rule">
<hr>
</div>
<p class="ibm-ind-link ibm-back-to-top"></p>
<p><span style="font-size: medium;"><a name="N101EE"><span class="atitle">小結:</span>
</a>
</span>
</p>
<p><span style="font-size: medium;">管道常用于兩個方面:(1)在shell中時常會用到管道(作為輸入輸入的重定向),在這種應用方式下,管道的創建對于用戶來說是透明的;(2)用于具有親緣關系的進程間通信,用戶自己創建管道,并完成讀寫操作。</span>
</p>
<p><span style="font-size: medium;">FIFO可以說是管道的推廣,克服了管道無名字的限制,使得無親緣關系的進程同樣可以采用先進先出的通信機制進行通信。</span>
</p>
<p><span style="font-size: medium;">管道和FIFO的數據是字節流,應用程序之間必須事先確定特定的傳輸"協議",采用傳播具有特定意義的消息。</span>
</p>
<p><span style="font-size: medium;">要靈活應用管道及FIFO,理解它們的讀寫規則是關鍵。</span>
</p>
<p>
??????? <span style="font-size: medium;"><a name="a"> </a>
附1:kill -l 的運行結果,顯示了當前系統支持的所有信號:
????? </span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;">1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGABRT 7) SIGBUS 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
</span>

</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<p><span style="font-size: medium;">除了在此處用來說明管道應用外,接下來的專題還要對這些信號分類討論。</span>
</p>
<p>
??????? <span style="font-size: medium;"><a name="b"> </a>
附2:對FIFO打開規則的驗證(主要驗證寫打開對讀打開的依賴性)
????? </span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;">#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;errno.h&gt;
#include &lt;fcntl.h&gt;
#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)&lt;0)&amp;&amp;(errno!=EEXIST))
printf("cannot create fifoserver/n");
handle_client(FIFO_SERVER);

}
int handle_client(char* arg)
{
int ret;
ret=w_open(arg);
switch(ret)
{
case 0:
{
printf("open %s error/n",arg);
printf("no process has the fifo open for reading/n");
return -1;
}
case -1:
{
printf("something wrong with open the fifo except for ENXIO");
return -1;
}
case 1:
{
printf("open server ok/n");
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;

}
</span>

</pre>
</td>
</tr></tbody></table>

linuxIPC——管道


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 天天夜干| 久久久久久久免费视频 | 亚洲一区二区三区网站 | 亚洲午夜综合网 | 91亚洲精品一区二区在线观看 | 中文字幕视频免费在线观看 | 欧美理论片大全在线观看 | 韩国日本一级毛片免费视频 | 国产在线观看成人免费视频 | 国产成人综合亚洲欧洲色就色 | 99久久综合狠狠综合久久aⅴ | 日韩一级不卡 | 免费一级真人毛片 | 久久综合五月 | 精品久久久久久18免费看 | 欧美精品一级毛片 | 亚洲国产福利精品一区二区 | 欧美午夜性刺激在线观看免费 | 伊人网综合在线观看 | 亚洲日本欧美日韩高观看 | 伊人久久成人 | 色久优优 欧美色久优优 | 国产亚洲精品久久午夜 | 伦理自拍| 亚洲精品色婷婷在线影院麻豆 | 日本高清一级片 | 欧美jizzhd精品欧美另类 | 亚洲五月综合缴情婷婷 | 日日碰| 波多野结衣免费一区二区三区香蕉 | 好色亚洲 | 久久大胆视频 | 精品国产一区二区三区不卡在线 | 99热久久国产精品免费看 | 999精品免费视频 | 亚洲精品国产一区二区三 | 久久一本色道综合 | 欧美日韩精选 | 一级成人黄色片 | 天天干天天干天天操 | 成人欧美一区二区三区视频不卡 |