read函數只是一個通用的讀檔案裝置的介面。是否阻塞需要由裝置的屬性和設定所決定。一般來說,讀字元終端、網路的socket描述字,管道檔案等,這些檔案的預設read都是阻塞的方式。如果是讀磁碟上的檔案,一般不會是阻塞方式的。但使用鎖和fcntl設定取消檔案O_NOBLOCK狀態,也會產生阻塞的read效果。
怎麼樣以非阻塞的方式從管道中讀取資料?因為我用read函數時,如果管道沒有資料就會阻塞住???
My Code是:
char chBuff[32];
read(file_pipe[0], chBuff, 16);
如果管道沒有資料我這個函數就永遠不返回,請問有沒有其它的方式,如果管道有資料就讀取,沒資料也立即返回??
或者在open的時候,傳入O_NONBLOCK參數,按非阻塞方式開啟 / fcntl(fd, F_SETFL, O_NONBLOCK)
在mode設定O_NONBLOCK標誌
每一個TCP套介面有一個發送緩衝區,可以用SO_SNDBUF套介面選項來改變這個緩衝區的大小。當應用進程調用 write時,核心從應用進程的緩衝區中拷貝所有資料到套介面的發送緩衝區。如果套介面的發送緩衝區容不下應用程式的所有資料(或是應用進程的緩衝區大於套介面發送緩衝區,或是套介面發送緩衝區還有其他資料),應用進程將被掛起(睡眠)。這裡假設套介面是阻塞的,這是通常的預設設定。核心將不從write系統調用返回,直到應用進程緩衝區中的所有資料都拷貝到套介面發送緩衝區。因此從寫一個TCP套介面的write調用成功返回僅僅表示我們可以重新使用應用進程的緩衝區。它並不告訴我們對端的
TCP或應用進程已經接收了資料。
TCP取套介面發送緩衝區的資料並把它發送給對端TCP,其過程基於TCP資料轉送的所有規則。對端TCP必須確認收到的資料,只有收到對端的ACK,本端TCP才能刪除套介面發送緩衝區中已經確認的資料。TCP必須保留資料拷貝直到對端確認為止。
1 輸入操作: read、readv、recv、recvfrom、recvmsg
如果某個進程對一個阻塞的TCP套介面調用這些輸入函數之一,而且該套介面的接收緩衝區中沒有資料可讀,該進程將被投入睡眠,直到到達一些資料。既然 TCP是位元組流協議,該進程的喚醒就是只要到達一些資料:這些資料既可能是單個位元組,也可以是一個完整的TCP分節中的資料。如果想等到某個固定數目的資料可讀為止,可以調用readn函數,或者指定MSG_WAITALL標誌。
既然UDP是資料報協議,如果一個阻塞的UDP套介面的接收緩衝區為空白,對它調用輸入函數的進程將被投入睡眠,直到到達一個UDP資料報。
對於非阻塞的套介面,如果輸入操作不能被滿足(對於TCP套介面即至少有一個位元組的資料可讀,對於UDP套介面即有一個完整的資料報可讀),相應調用將立即返回一個EWOULDBLOCK錯誤。
2 輸出操作:write、writev、send、sendto、sendmsg
對於一個TCP套介面,核心將從應用進程的緩衝區到該套介面的發送緩衝區拷貝資料。對於阻塞的套介面,如果其發送緩衝區中沒有空間,進程將被投入睡眠,直到有空間為止。
對於一個非阻塞的TCP套介面,如果其發送緩衝區中根本沒有空間,輸出函數調用將立即返回一個EWOULDBLOCK錯誤。如果其發送緩衝區中有一些空間,傳回值將是核心能夠拷貝到該緩衝區中的位元組數。這個位元組數也稱為不足計數(short count)
UDP套介面不才能在真正的發送緩衝區。核心只是拷貝應用進程資料並把它沿協議棧向下傳送,漸次冠以UDP頭部和IP頭部。因此對一個阻塞的UDP套介面,輸出函數調用將不會因為與TCP套介面一樣的原因而阻塞,不過有可能會因其他的原因而阻塞