1. 程式人生 > >Linux C網路程式設計

Linux C網路程式設計

TCP長連線和短連線

短連線

連線->傳輸資料->關閉連線

WEB網站的http服務一般都用短連結,因為長連線對於服務端來說會耗費一定的資源,而像WEB網站這麼頻繁的成千上萬甚至上億客戶端的連線用短連線會更省一些資源,如果用長連線,而且同時有成千上萬的使用者,如果每個使用者都佔用一個連線的話,那可想而知吧。所以併發量大,但每個使用者無需頻繁操作情況下需用短連好。

長連線
連線->傳輸資料->保持連線 -> 傳輸資料-> 。。。 ->關閉連線。

長連線多用於操作頻繁,點對點的通訊,而且連線數不能太多情況。
每個TCP連線都需要三步握手,這需要時間,如果每個操作都是先連線,再操作的話那麼處理速度會降低很多,
所以每個操作完後都不斷開,下次次處理時直接傳送資料包就OK了,不用建立TCP連線。

阻塞與非阻塞方式 
1.非阻塞方式
讀函式不停地進行讀動作,如果沒有報文接收到,等待一段時間後超時返回,這種情況一般需要指定超時時間。
2.阻塞方式
如果沒有報文接收到,則讀函式一直處於等待狀態,直到有報文到達。 

tcp協議本身是可靠的,並不等於應用程式用tcp傳送資料就一定是可靠的.不管是否阻塞,send傳送的大小,並不代表對端recv到多少的資料.

int send( SOCKET s, const char FAR *buf, int len, int flags );

不論是客戶還是伺服器應用程式都用send函式來向TCP連線的另一端傳送資料。客戶程式一般用send函式向伺服器傳送請求,而伺服器則通常用send函式來向客戶程式傳送應答。

該函式的第一個引數指定傳送端套接字描述符;

第二個引數指明一個存放應用程式要傳送資料的緩衝區;

第三個引數指明實際要傳送的資料的位元組數;

第四個引數一般置0。

send()僅僅是把應用層buffer的資料拷貝進socket的核心傳送buffer中,傳送是TCP的事情,和send其實沒有太大關係。接收緩衝區被TCP用來快取網路上來的資料,一直儲存到應用程序讀走為止。對於TCP,如果應用程序一直沒有讀取,接收緩衝區滿了之後,發生的動作是:收端通知發端,接收視窗關閉(win=0)。這個便是滑動視窗的實現。保證TCP套介面接收緩衝區不會溢位,從而保證了TCP是可靠傳輸。因為對方不允許發出超過所通告視窗大小的資料。 這就是TCP的流量控制,如果對方無視視窗大小而發出了超過視窗大小的資料,則接收方TCP將丟棄它。

int recv( SOCKET s, char FAR *buf, int len, int flags);

不論是客戶還是伺服器應用程式都用recv函式從TCP連線的另一端接收資料。該函式的第一個引數指定接收端套接字描述符;

第二個引數指明一個緩衝區,該緩衝區用來存放recv函式接收到的資料;

第三個引數指明buf的長度;

第四個引數一般置0。

套接字有兩種模式,阻塞模式與非阻塞模式。預設建立的為阻塞模式.

1. 同步,就是我呼叫一個功能,該功能沒有結束前,我死等結果。
2. 非同步,就是我呼叫一個功能,不需要知道該功能結果,該功能有結果後通知我(回撥通知)
3. 阻塞,      就是呼叫我(函式),我(函式)沒有接收完資料或者沒有得到結果之前,我不會返回。
4. 非阻塞,  就是呼叫我(函式),我(函式)立即返回,通過select通知呼叫者

阻塞I/O模型:

阻塞I/O模型圖:在呼叫recv()/recvfrom()函式時,發生在核心中等待資料和複製資料的過程。

1334216532_9745.jpg

當使用socket()函式和WSASocket()函式建立套接字時,預設的套接字都是阻塞的。這意味著當呼叫Windows Sockets API不能立即完成時,執行緒處於等待狀態,直到操作完成。

使用阻塞模式的套接字,開發網路程式比較簡單,容易實現。當希望能夠立即傳送和接收資料,且處理的套接字數量比較少的情況下,使用阻塞模式來開發網路程式比較合適。

阻塞模式套接字的不足表現為,在大量建立好的套接字執行緒之間進行通訊時比較困難。當使用“生產者-消費者”模型開發網路程式時,為每個套接字都分別分配一個讀執行緒、一個處理資料執行緒和一個用於同步的事件,那麼這樣無疑加大系統的開銷。其最大的缺點是當希望同時處理大量套接字時,將無從下手,其擴充套件性很差

非阻塞IO模型

我們把一個SOCKET介面設定為非阻塞就是告訴核心,當所請求的I/O操作無法完成時,不要將程序睡眠,而是返回一個錯誤。這樣我們的I/O操作函式將不斷的測試資料是否已經準備好,如果沒有準備好,繼續測試,直到資料準備好為止。在這個不斷測試的過程中,會大量的佔用CPU的時間。

1334216607_3004.jpg

當使用socket()函式和WSASocket()函式建立套接字時,預設都是阻塞的。在建立套接字之後,通過呼叫ioctlsocket()函式,將該套接字設定為非阻塞模式。Linux下的函式是:fcntl().
   套接字設定為非阻塞模式後,在呼叫Windows Sockets API函式時,呼叫函式會立即返回。大多數情況下,這些函式呼叫都會呼叫“失敗”,並返回WSAEWOULDBLOCK錯誤程式碼。說明請求的操作在呼叫期間內沒有時間完成。通常,應用程式需要重複呼叫該函式,直到獲得成功返回程式碼。

後面還會再發一篇串列埠多執行緒讀寫的博文,感覺自己Level Low,慢慢來吧,畢竟很多年前我的C語言考了36分。