套接字預設狀態是阻塞的。也就是說當發出乙個不能立即完成的套接字呼叫時,程序將被投入睡眠,等待相應操作的完成 ,一般分為四類:
1. 輸入操作:包括read、readv、recv、recvfrom、recvmsg這5個函式。當套接字緩衝區沒資料可讀時,程序將被投入睡眠狀態,直到有資料可達。
2. 輸出操作:包括write、writev、send、snedto和sendmsg這5個函式。
如果傳送緩衝區沒有空間,則程序將被投入睡眠,因為這些操作需要將應用程序緩衝區的資料拷貝到套接字的傳送緩衝區的資料
(udp不存在真正的傳送緩衝,核心只是複製資料並把他們沿著協議棧向下傳送並依次包裝udp首部和ip首部)。
3. 接收連線:accept函式,這個就很熟悉了,當伺服器等待客戶端外來連線的到來時將被投入睡眠。
4. 建立連線:根據乙個tcp三路握手的過程,connect函式至少阻塞乙個rtt的時間(自己的syn傳送和伺服器的ack的接收)。
主要複雜之處在於緩衝區的管理,設想乙個場景:
如果標準輸入可讀,read返回,接著呼叫write,然而,如果這個時候套接字傳送緩衝區已經滿了,則write會阻塞,當write阻塞的時間裡面,很有可能有來自接收緩衝區的資料可讀;
1.複雜版本,使用select+非阻塞i/o
(1).fcntl將標準輸入、標準輸出和網路套接字描述符都設定為非阻塞模式。
(2)呼叫select之前對4中情況進行判斷。
(3).四種套接字可讀或者可寫後的操作,細節先忽略。
2.簡單版本,使用fork多執行緒
函式一開始就把程序劃分為父程序和子程序,父程序用來把標準輸入的文字複製到伺服器,子程序用來將回射的文字複製到標準輸出。
從圖中可以看到,儘管只有乙個套接字(父子程序共享),但由於tcp是全雙工的,並且這個套接字有兩個描述符(fork子程序時完成拷貝),所以父程序可以往裡寫,而子程序可以從中讀。
這裡需要注意一些邊界條件,例如伺服器關閉,客戶子程序將收到eof,此時子程序需要給父程序乙個sigterm以防止父程序仍在執行。
另外,父程序中要用shutdown而不是close,因為此時是多程序共享描述符,引用計數大於1。
#include "unp.h"
void str_cli(file *fp, int sockfd)
/* parent: stdin -> server */
while (fgets(sendline, maxline, fp) != null)
writen(sockfd, sendline, strlen(sendline));
shutdown(sockfd, shut_wr); /* eof on stdin, send fin */
pause();
return;
}
當在乙個非阻塞的套接字上呼叫connect的時候,會立刻返回乙個einprogress錯誤,不過tcp三路握手連線將繼續進行。當呼叫connect後,我們可以使用select檢測這個連線成功、失敗。非阻塞connect主要有三個用途:
1. 三路握手的同時進行其他處理;
2. 同時建立多個連線,例如web伺服器;
3. 減少connect的超時等待時間;
利用非阻塞的connect可以構建乙個web客戶端,例如我們在與乙個web伺服器建立乙個http連線的時候,我們會獲取乙個homepage,隨後這個主頁往往還有對其他網頁的引用,客戶可以通過非阻塞的connect並行地獲取多個網頁,而不是阻塞地序列獲取,這樣就提高了效率。(考慮到tcp的擁塞避免機制,他對網路是不利的)
linux shell程式設計指南第十六章
乙個s h e l l指令碼可以包含乙個或多個命令。當然可以不必只為了兩個命令就編寫乙個s h e l l 指令碼,一切由使用者自己決定。s h e l l指令碼可以在行命令中接收資訊,並使用它作為另乙個命令的輸入。指令碼不是複雜的程式,它是按行解釋的。指令碼第一行總是以 b i n s h開始,這...
第十六章 tcp wrappers
在伺服器向外提供的tcp服務上包裝一層安全檢測機制。外來連線請求首先通過這個安全檢測,獲得安全認證後才可被系統服務接受。hosts.allow hosts.deny 在配置檔案中為各服務分別定義訪問控制規則實現訪問控制,檔案中的規則是即時生效的。配置檔案語法 1 daemon list client...
第十六章 執行緒棧
1 基礎 1 執行緒初始化時,執行緒棧預設1m,所有頁面都是page readwrite屬性,但只為前兩個頁面調撥了物理儲存器,位址低的那個頁面叫防護頁面,為其指定了page guard屬性 2 當執行緒訪問到防護頁面時,由於指定了page guard屬性,系統會得到通知,系統會為防護頁面的下乙個頁...