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()函數。

然後就可以互相通信傳遞數據了。


代碼如下:



運行之後將喚醒服務器端程序,服務器端程序喚醒後的運行結果如下:



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