亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 1247 | 回復: 0
打印 上一主題 下一主題

《UNP》-IPC學習筆記(2):管道和FIFO [復制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2009-07-14 16:50 |只看該作者 |倒序瀏覽
1、概述
管道是最初的UNIX IPC形式,由于管道沒有名字,所以只能在用于有親緣關(guān)系的進程(所謂的親緣關(guān)系是指進程間有共同的祖先)。FIFO則被稱為命名管道。
先說明fork,exec,_exit函數(shù)對管道及fifo函數(shù)的影響:
fork:子進程取得父進程的管道以及fifo描述字的拷貝。
exec:所有代開的描述字依舊打開,除非已經(jīng)設(shè)置描述字的FD_CLOEXEC位。
_exit:關(guān)閉所有打開的描述字,最后一個描述字關(guān)閉時刪除管道與FIFO中的數(shù)據(jù)。
管道和FIFO涉及的函數(shù)有:pipe, mkfifo, fcntl, open, read, write, close, unlink.
2、管道函數(shù)及說明:int pipe(int fd[2]);
(1)、這個函數(shù)提供一個單向管道。fd是輸出參數(shù),fd[0]用來讀出,fd[1]用來寫入(這里的讀出和寫入是的賓語是管道)。函數(shù)成功返回0,錯誤返回-1.
注意:a、linux的system call(相當于系統(tǒng)API)函數(shù)的返回值是成功返回0,返回其他的就表示出錯,而windows的api函數(shù)則剛好相反,錯誤返回0,成功返回其他。b、這里不寫函數(shù)的頭文件,要知道它用到那些頭文件,在類unix下用man來查看即可,如:man 2 pipe,2表示pipe是一個系統(tǒng)調(diào)用,如果是c函數(shù)庫里面的函數(shù)則按3。
(2)、管道的典型用途如下(用來作為父子進程消息的共享):
a、創(chuàng)建管道1(int fd1[2]) 和管道2(int fd2[2]);
b、fork創(chuàng)建子進程
c、父進程關(guān)閉管道1的讀出端和2的寫入端(fd1[0],fd2[1])
d、子進程關(guān)閉管道2的讀出端和1的寫入端(fd1[1],fd2[0])
代碼如下:
int pipe1[2];
int pipe2[2];
pid_t childPid;
pipe(pipe1);
pipe(pipe2);

if( ( childPid = fork()) == 0 ) /* child process */
{
    close(pipe1[1]);
    close(pipe2[0]);
    ...   /* your code */
}
/* parent process */
close(pipe1[0]);
close(pipe2[1]);
...
waitpid(childPid, NULL, 0);
...
子進程在這里用來專門做一件事情,像服務(wù)器。而父進程就相當于客戶端。如是,子進程在完成任務(wù)之后就exit(0),那么但子進程終止時候變成僵尸進程(zombie),內(nèi)核給父進程發(fā)送一個信號SIGCHILD,但是父進程沒有撲抓,缺省行為是忽略;父進程后面調(diào)用到waitpid的時候就可以等待childPid進程的終止,取得終止狀態(tài)。如果沒有waitpid而直接返回,則父進程返回后那個僵尸子進程將成為托孤給init進程的孤兒進程。內(nèi)核將為init進程發(fā)送SIGCHILD信號。
這樣子,就變成: 客戶-->管道fd1-->服務(wù)器;服務(wù)器-->fd2-->客戶
3、fifo 有名管道(fifo的意思是:先進先出)
也是一個半雙工的單向數(shù)據(jù)流,但是有一個路徑名與之相連。函數(shù)如下:
int mkfifo(const char *pathname, mode_t mode);
說明:
a、mkfifo函數(shù)已經(jīng)隱含制訂了O_CREAT | O_EXCL也就是說如果pathname那個管道已經(jīng)存在,則返回一個錯誤值EEXIST,如果想打開一個已經(jīng)存在的管道,用open()即可。
b、由于fifo是先進先出的,所以write函數(shù)總是往管道末尾寫入數(shù)據(jù),而read函數(shù)總是從管道的開頭返回數(shù)據(jù),如果用lseek定位文件指針,會返回ESPIPE錯誤。
應用:
/* server.c */
...
if( ( mkfifo(FIFO1, FILE_MODE )
if( ( mkfifo(FIFO2, FILE_MODE )
readfd = open(FIFO1, O_RDONLY, 0);
writefd = open(FIFO2, O_WRONLY, 0);
/* your code */
exit(0);
這是服務(wù)器進程的FIFO,其中FIFO1,F(xiàn)IFO2可以定義一個宏來指定,比如,#define FIFO1 "/temp/fifo.1"(路徑名隨意,不過由于是臨時的文件,一般放在/temp目錄下,權(quán)限比較低嘛)
打開文件之后就可以用read,write函數(shù)往管道讀寫信息了,F(xiàn)IFO1,F(xiàn)IFO2就是像文件描述符。
再看client的代碼:
/* client.h */
writefd = open(FIFO1, O_WRONLY, 0);
readfd = open(FIFO2, O_RDONLY, 0);
/* your code */

close(writefd);
close(readfd);

unlink(FIFO1);
unlink(FIFO2);
exit(0);
說明:a、通常管道是由服務(wù)器建立,由客戶端銷毀(unlink函數(shù)),close只是關(guān)閉管道而已。b、注意clinet.h上的那兩個open和server.h上的那兩個open的順序,否則會引起死鎖(見后面)
4、阻塞態(tài)下的規(guī)則(阻塞態(tài)是默認的狀態(tài)):
(1)、管道和FIFOopen函數(shù)的返回結(jié)果:
writefd = open(FIFO1, O_WRONLY, 0); 這個是用只寫方式打開管道,如果FIFO1此時已經(jīng)有別的進程以只讀方式打開(就是說在這條代碼運行之前,已經(jīng)有代碼open(FIFO1, O_RDONLY, 0)運行),則此函數(shù)返回成功,否則,將會阻塞到有別的進程以只讀方式打開FIFO1為止。反過來也一樣。
(2)、read函數(shù)作用于管道和FIFO 的返回結(jié)果:
如果FIFO1為空(就是說里面沒有數(shù)據(jù)):該管道以只讀方式打開,則返回0;FIFO1以只寫方式打開,則阻塞到FIFO1有數(shù)據(jù)或者是FIFO1不再以寫方式打開為止。
(3)、write函數(shù)作用于管道和FIFO的返回結(jié)果:
如果FIFO1沒有以只讀方式打開,則給進程產(chǎn)生SIGPIPE信號(缺省行為是終止該進程);如果已經(jīng)以只讀方式打開,則見下。
(4)、write操作的原子性:
如果寫入數(shù)據(jù)的字節(jié)數(shù)小于等于PIPE_BUF,則該函數(shù)保證其原子性;否則不能保證。
現(xiàn)在來看一下上面那個程序,服務(wù)器代碼先運行,因此:當起運行到readfd = open(FIFO1, O_RDONLY, 0);的時候,還沒有任何進程以O(shè)_WRONLY方式打開FIFO1,進程阻塞在這里;
然后客戶端代碼開始運行,但運行到這個地方的時候:writefd = open(FIFO1, O_WRONLY, 0);服務(wù)器阻塞的地方開始釋放,而在客戶端,因為FIFO1在服務(wù)器已經(jīng)是以O(shè)_RDONLY打開了,所以繼續(xù)運行。
如果客戶端的這兩個open交換一個順序,那么readfd = open(FIFO2, O_RDONLY, 0);先運行,則由于FIFO2還沒有以O(shè)_WRONLY方式打開,所以客戶端也阻塞,客戶和服務(wù)器都阻塞,大家都在等對方的資源,這種情況我們稱之為死鎖(deadlock)
5、非阻塞態(tài)下的規(guī)則:
(1)、非阻塞態(tài)的設(shè)置。
a、調(diào)用open時可以指定 readfd = open(FIFO1, O_RDONLY | O_NONBLOCK );
b、如果readfd已經(jīng)打開,則可以用fcntl來設(shè)置O_NONBLOCK標志。
(2)、對open操作的影響:
如果當前操作是wrfd = open(FIFO1, O_WRONLY | O_NONBLOCK, 0); 那么如果是FIFO1在此以前沒有用O_RDONLY方式打開過,返回ENOXIO錯誤,否則都成功返回。
(3)、對空管道或空FIFO read操作的影響:read(readfd, ...); 如果該readfd對應的FIFO用O_WRONLY打開返回0,否則返回EAGAIN。
(4)、對write操作的影響同阻塞態(tài)下。
6、技巧:單個服務(wù)器多個客戶時候,服務(wù)器中有連續(xù)的兩行代碼:
readfifo = open(SERV_FIFO, O_RDONLY, 0);
dummy = open(SERV_FIFO, O_WRONLY, 0);
作用:a、服務(wù)器運行到readfifo,阻塞,直到有客戶用O_WRONLY打開SERV_FIFO為止。然后因為SERV_FIFO已經(jīng)以O(shè)_RDONLY打開,因此這個dummy成功返回。
b、到客戶完成任務(wù),關(guān)閉SERV_FIFO時,SERV_FIFO變成空,因此,服務(wù)器在運行到read語句的時候,阻塞知道下一個客戶以O(shè)_WRONLY方式打開SERV_FIFO為止(也就是直到有下一個用戶請求為止)
7、Dos攻擊(拒絕服務(wù)型攻擊)
有見上面的阻塞,有個攻擊方法就是說,發(fā)送一條請求,但是從來不打開自己的FiFO,讓服務(wù)器死等。服務(wù)器一直阻塞,沒辦法用了。
當然,現(xiàn)在的服務(wù)器都是并發(fā)性服務(wù)器,最多只能阻塞他的一個子進程;但是即使在這種情況下一樣可以進行Dos攻擊,方法是發(fā)送大量的請求,以至于服務(wù)器開辟的進程達到極限,而且每個子進程都用上面的辦法來阻塞。(此時不但服務(wù)器進程被阻塞了,整個服務(wù)器系統(tǒng)都被阻塞了)。
8、字節(jié)流
管道和FIFO是以字節(jié)流的方式來傳遞信息的,類似于TCP。那么怎樣區(qū)分信息的界限呢?有下面三種常用的技巧:
a、帶內(nèi)特殊終止符:分隔標志(類似與SLIP的標記)
b、顯示長度在信息頭:像TCP協(xié)議棧實現(xiàn)。
c、每次連接一個記錄:像HTTP1.0協(xié)議實現(xiàn)。
本文來自CSDN博客,轉(zhuǎn)載請標明出處:
http://blog.csdn.net/jiangnanyouzi/archive/2008/10/31/3193722.aspx


本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u/15201/showart_1996113.html
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP