標籤:
轉:http://blog.csdn.net/xywlpo/article/details/6639748
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函數的工作流程。
- 阻塞模式下的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協議。
TCP/IP的Socket編程