TCP/IP的Socket編程

1. TCP/IP、UDP的基本概念

TCP/IP(Transmission Control Protocol/Internet Protocol)即傳輸控制協議/網間協議,他是一個工業標準的協議集,它是爲廣域網設計的。其中包含了很多其他的協議,不過以TCP和IP協議爲代表。UDP(User Data Protocl),即用戶數據報協議,是與TCP相對應的協議,它屬於TCP/IP協議族中的一個。
TCP/IP進行數據傳輸主要分爲兩個過程:建立連接過程和數據傳輸過程。
  • TCP/IP協議通過三次握手建立一個可靠的連接,步驟:
    • 第一次握手:建立連接時,客戶端發送syn包(syn=j)到服務器,並進入SYN_SEND狀態,等待服務器確認;
    • 第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也發送一個SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態;
    • 第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次握手。

  • 數據傳輸過程:發送端發送數據,然後進入等待ACK確定信號狀態,隨後接收端接收到數據,發送ACK確認信號,發送端接收到ACK後才發送下一組數據,同時發送端有一個定時器,定時時間到了沒有接收到ACK,就認爲發送失敗了,進行重新發送。因爲發送端發送完數據後處於等待狀態,因此爲了提高效率,引入“滑動窗口”的概念,就是發送的時候一次發送多組數據,相當於窗口的大小,然後當接收到第一個ACK後,就將窗口向後移動一個數據,就形成了滑動窗口的情況。

下表顯示了協議間的關係:

  


2. Socket的基本概念

Socket是應用層與TCP/IP協議族通信的中間軟件抽象層,它是一組接口,在設計模式中,Socket就是一個門面模式,它把複雜的TCP/IP協議族隱藏在了Scoket接口的後面,讓Socket去組織數據,以符合指定的協議。

3. Socket的使用

舉個簡單的例子先:你要打電話給一個朋友,先撥號,朋友聽到電話鈴聲後提取電話,這時你和你的朋友就建立起了連接,就可以講話了,等交流結束,掛斷電話結束此次交談,這個生活場景的例子就解釋了TCP/IP的工作原理和流程,其具體的流程圖如下所示:
服務器端工作流程:
  • 使用WSAStartup()函數檢查系統協議棧安裝情況
  • 使用socket()函數創建服務器端通信套接口
  • 使用bind()函數將創建的套接口與服務器地址綁定
  • 使用listen()函數使服務器套接口做好接收連接請求準備
  • 使用accept()接收來自客戶端由connect()函數發出的連接請求
  • 根據連接請求建立鏈接後,使用send()還唸書發送數據,或者使用recv()函數接收數據
  • 使用closesocket()函數關閉套接口(可以先用shutdown()函數吸納關閉讀寫通道)
  • 最後調用WSACleanup()函數結束Winsock Sockets API


客戶端工作流程
  • 使用WSAStartup()函數檢查系統協議棧安裝情況
  • 使用socket()函數創建客戶端套接口
  • 使用connect()函數發出與服務器建立連接的請求(調用前可以不用bind()端口號,由系統自動完成)
  • 連接建立後使用send()函數發送數據,或使用recv()函數接收數據
  • 是喲個closesocket()函數關閉套接口
  • 最後掉壓迫能夠WSACleanup()函數,結束Winsock Sockets API

4. Socket的send和recv函數

socket的發送和接收緩存區是兩個相互獨立的緩存區。socket的send和recv函數分爲阻塞模式的和非阻塞模式的,在定義socket的時候,默認設置爲了阻塞模式,而後如果想要改變爲非阻塞模式,只需使用ioctlsocket函數進行設置即可。非阻塞模式一旦調用即刻返回,因此如果傳輸數據較爲稀疏,則會經常返回失敗信息,爲此一般使用循環來接收數據。而常用的方式是阻塞模式,send函數沒啥問題,而recv函數一般配合select函數,可以做到雖然recv是阻塞的,但是合起來的效果是阻塞一段時間的方式。下面給出send和recv函數的工作流程。
  1. 阻塞模式下的send和recv函數

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

不論是客戶還是服務器應用程序都用send函數來向TCP連接的另一端發送數據。

客戶程序一般用send函數向服務器發送請求,而服務器則通常用send函數來向客戶程序發送應答。

該函數的第一個參數指定發送端套接字描述符;

第二個參數指明一個存放應用程序要發送數據的緩衝區;

第三個參數指明實際要發送的數據的字節數;

第四個參數一般置0。

這裏只描述同步Socket的send函數的執行流程。當調用該函數時,send先比較待發送數據的長度len和套接字s的發送緩衝的長度,如果len大於s的發送緩衝區的長度,該函數返回SOCKET_ERROR;如果len小於或者等於s的發送緩衝區的長度,那麼send先檢查協議 是否正在發送s的發送緩衝中的數據,如果是就等待協議把數據發送完,如果協議還沒有開始發送s的發送緩衝中的數據或者s的發送緩衝中沒有數據,那麼 send就比較s的發送緩衝區的剩餘空間和len,如果len大於剩餘空間大小send就一直等待協議把s的發送緩衝中的數據發送完,如果len小於剩餘 空間大小send就僅僅把buf中的數據copy到剩餘空間裏(注意並不是send把s的發送緩衝中的數據傳到連接的另一端的,而是協議傳的,send僅僅是把buf中的數據copy到s的發送緩衝區的剩餘空間裏)。如果send函數copy數據成功,就返回實際copy的字節數,如果send在copy數據時出現錯誤,那麼send就返回SOCKET_ERROR;如果send在等待協議傳送數據時網絡斷開的話,那麼send函數也返回SOCKET_ERROR。

要注意send函數把buf中的數據成功copy到s的發送緩衝的剩餘空間裏後它就返回了,但是此時這些數據並不一定馬上被傳到連接的另一端。

注意:在Unix系統下,如果send在等待協議傳送數據時網絡斷開的話,調用send的進程會接收到一個SIGPIPE信號,進程對該信號的默認處理是進程終止。


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

不論是客戶還是服務器應用程序都用recv函數從TCP連接的另一端接收數據。

該函數的第一個參數指定接收端套接字描述符;

第二個參數指明一個緩衝區,該緩衝區用來存放recv函數接收到的數據;

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

第四個參數一般置0。

這裏只描述同步Socket的recv函數的執行流程。當應用程序調用recv函數時,recv先等待s的發送緩衝 中的數據被協議傳送完畢,如果協議在傳送s的發送緩衝中的數據時出現網絡錯誤,那麼recv函數返回SOCKET_ERROR,如果s的發送緩衝中沒有數 據或者數據被協議成功發送完畢後,recv先檢查套接字s的接收緩衝區,如果s接收緩衝區中沒有數據或者協議正在接收數據,那麼recv就一直等待,只到 協議把數據接收完畢。當協議把數據接收完畢,recv函數就把s的接收緩衝中的數據copy到buf中(注意協議接收到的數據可能大於buf的長度,所以 在這種情況下要調用幾次recv函數才能把s的接收緩衝中的數據copy完。recv函數僅僅是copy數據,真正的接收數據是協議來完成的),recv函數返回其實際copy的字節數。如果recv在copy時出錯,那麼它返回SOCKET_ERROR;如果recv函數在等待協議接收數據時網絡中斷了,那麼它返回0。

2. 非阻塞模式

非阻塞模式就是一旦調用,如果不滿足copy條件,則函數馬上返回失敗信息。

5. Winsock編程流程(以服務器端爲例)

1. 使用WSAStartup()裝載檢查TCP/IP協議

2. 創建套接字,有三種類型的套接字供選擇:流式套接字(用於TCP),數據報套接字(UDP)和原始套接字(底層協議)

3. 將創建好的套接字和IP地址以及端口進行綁定

4. 使用getsockopt獲得套接口的參數,使用setsockopt設置套接口的參數(主要設置套接口的收發緩存大小),使用ioctlsocket

設置阻塞還是非阻塞的模式(這裏的阻塞和非阻塞模式指的是API函數是否調用完馬上返回)

5. 進行通信,在通信的部分,windows socket給我們提供了五種I/O模型用於收發通信:(他們都可以和阻塞或非阻塞函數一起

使用)

a. select模型,常用的模型,以select函數爲核心,可以監控套接口是否有數據收發。它是同步模型。

b. WSAAsyncSelect模型,異步I/O模型,利用windows的消息機制實現異步接收,需要有窗口接收消息,只有接收數據是

異步的。

c. WSAEventSelect 模型,異步I/O模型,通過事件觸發來實現異步接收,它不需要接收窗口。

d. 重疊模型:比較完美的模型。

e. 完成端口:最爲複雜的I/O模型,當需要一個進程管理很多的套接口的時候,很適合使用這種模型。

6. 使用closesocket()函數關閉套接口的收發。

7. 使用WSACleanup()函數卸載TCP/IP協議。 










發佈了34 篇原創文章 · 獲贊 60 · 訪問量 40萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章