1. 程式人生 > >TCP套接字程式設計—具體流程梳理

TCP套接字程式設計—具體流程梳理

一個上午都在除錯一個伺服器端監聽程式,測試的客戶端怎麼都連不上,然後瘋狂在網上搜尋答案無果,最後無意中發現竟是系統沒有聯網。唉,頓時就像是在debug過程中發現某處少了一個逗號是一個樣的鬱悶!不過這個糾結的過程卻讓我把TCP套接字程式設計的整個過程又有了重新的認識。

TCP是一種可靠的面向連線的通訊協議,因此在通訊之前需要確認通訊的雙方,稱之為客戶端和伺服器端。一般由客戶端向伺服器端傳送連線請求,然後伺服器端確認請求,最後客戶端再確認連線,即為三次握手。在TCP套接字網路程式設計中,存在更多的細節,大致的流程如下圖所示:


通俗地說,由TCP資料報首部結構我們知道,唯一標識一個TCP連線的結構是一個插口對,也就是客戶端ip、客戶端埠、伺服器端ip、伺服器端埠四元組。這個四元組結構就是一個套接字。在客戶端中,我們知道自己的ip、埠(使用者定義或者核心分配),也知道目的伺服器的插口地址,而在伺服器端的套接字只有伺服器本身的插口地址,在有客戶端來連線的時候配成一個新的已連線的套接字。

伺服器端:

1、建立一個套接字:呼叫socket()函式,將返回一個套接字描述符sockfd;

2、為建立的套接字繫結本地插口地址:因為由socket()函式建立的套接字所包含的資訊很少,只有一些協議族和型別等

   ,並沒有指定任何的地址,因此需要建立一個套接字地址結構物件,初始化後繫結到建立的套接字上,即下一步的操       作。

3、將套接字繫結到本地插口地址上:建立一個本地套接字地址結構物件(sockaddr_in),然後通過bind()函式將這個對      象和前面的套接字繫結。

4、好了,伺服器端的套接字有本地插口地址了,這個套接字是用來監聽的,也就是說這個套接字是用來監聽是否有指向      該伺服器端的連線請求,由listen()函式將這個套接字變成監聽套接字

5、監聽套接字還是不完整的,它是一個沒有源端插口地址的套接字,因此當有客戶端連線到該伺服器端的時候,就會與      監聽套接字“組合”成一個完整的已連線套接字了(當然不是真的組合,可以這麼來理解這個過程)。伺服器端是通      過accept()函式來建立一個已連線套接字。

注意區分監聽套接字和已連線套接字:監聽套接字是在伺服器的生命期過程中一直存在的。而已連線套接字是由核心為每個與伺服器連線的客戶端建立的。後者在完成給定客戶端服務時候被關閉。

基本過程就是這樣,下面是一個最簡單的獲取客戶端ip地址和埠號的伺服器端程式:


在這裡,accept()函式來讀取已完成連線佇列中客戶端請求,如果佇列為空,則使得伺服器端程序陷入休眠狀態,直到有客戶端請求完成連線被喚醒。此時沒有客戶端連線請求時,執行結果如下:


即陷入休眠狀態。

客戶端:

1、建立一個套接字:呼叫socket()函式,返回一個套接字描述符sockfd;

2、這裡有個需要注意的地方,就是客戶端的套接字需不需要bind一個本地插口地址。(前一篇博文中有說)一般沒有        這個需要。但是我們需要一個目的伺服器端的插口地址,但是不是用來繫結到套接字上面,而是用來connect到服務      器端。

3、呼叫connect()函式後,客戶端出發三次握手。發出請求到完成三次握手過程中,客戶端的連線請求將進入伺服器端      的未完成連線佇列,完成三次握手後將進入已完成連線佇列中,後者將會喚醒伺服器端的程序,從而繼續執行              accept()函式。

然後就可以互相通訊傳遞資料了。

程式碼如下:

執行之後將喚醒伺服器端程式,伺服器端程式喚醒後的執行結果如下: