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分。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章