TCP/IP学习笔记(二)TCP三次握手
TCP是一種面向連接的流傳輸協議,提供了對數據傳輸時的各種控制功能,比如
- 當丟包時可以重新發送
- 即使數據到達順序錯亂也可以保證數據的有序性
由于TCP是面向連接的協議,所以必須在確定通信對端存在時才會發送數據,即三次握手。
好比于A和B打電話,電話撥通后
A對B說:”你好,我是A,你能聽見我說話嗎”(第一次握手)
B聽到A的詢問回答說:”你好,我能聽見你說話,你能聽見我說話嗎”(第二次握手)
A聽見B的回復后告訴B說:”我也能聽見你說話”(第三次握手)
此時A和B都已確定對方能夠聽見自己的聲音,即A和B的通訊連接已經建立
三次握手
三次握手主要需要解決以下三個問題
- 要使每一方能夠知道對方的存在
- 要允許雙方協商一些參數(如最大窗口值,是否使用窗口擴大選項和時間戳選項以及服務質量等)
- 能夠對運輸實體資源(如緩存大小,連接表中的項目等)進行分配
三次握手的時序圖如下,其中,客戶端進行主動連接,稱為主動打開(執行connect),而服務器進行連接請求的接收,稱為被動打開(執行accept)
三次握手流程
第一次握手
- 客戶端調用connect函數,請求連接服務器,并發送連接請求報文段,此時報文首部的同步位SYN = 1,同時選擇一個初始序列號seq = x放在報文段中。此時客戶端狀態變為SYN_SENT,表示同步已發送。
當電話接通后A詢問B:”你能聽見我說話嗎?”
TCP規定,SYN = 1的報文段不能攜帶數據,但是需要消耗一個序列號
第二次握手
- 服務器調用accept函數,當收到客戶端的連接請求后,將收到的報文段記錄在本地(獲取序列號信息),隨后發送自己的報文段,該報文段中的SYN位和ACK位都被置為1,表示既是一個同步報文也是一個應答報文。此外,報文中需要包含自己的初始序列號sqe = y以及希望下次收到的數據的序列號,由于剛才收到的序列號為x,所以下次希望接受的序列號為x + 1。至此服務器狀態變為SYN_RCVD,表示同步已收到。
B回復A說:”我能聽見你說話,你能聽見我說話嗎?”
TCP規定,該報文段也不能攜帶數據,但是也需要消耗一個序列號
第三次握手
- 客戶端收到服務器的報文段后發送確認報文段,該報文段首部ACK確認位被置1,序列號為x + 1,希望下次接收的數據序列號為y + 1。隨后狀態變為ESTABLISHED,connect函數返回。
- 服務器收到客戶端發來的確認報文段,確認連接建立,狀態變為ESTABLISHED,accept函數返回
A聽到B的回復后確認B能聽見自己的聲音,同時告訴B自己也能聽見他的聲音。B聽見A的回復后確認A能聽見自己的聲音,此時雙方可以正常進行通話
文件描述符耗盡時的accept處理
accept會先后執行兩步,任何位置出錯都會直接返回
- 選擇一個空閑的文件描述符充當套接字描述符
- 從TCP緩沖區的連接隊列中取出一個連接請求,創建連接
然而考慮一種極端情況,當服務器本地文件描述符耗盡時,accept在第一步就會出錯返回,根本沒有從緩沖區中取出連接請求。此時如果重新判斷,那么監聽套接字仍然是可讀的,又開始accept,結果又發現耗盡,就會造成死循環。
解決的辦法就是想辦法讓accept正常返回,成功接收請求。可以在服務器初始化時占用一個空閑描述符(通常是打開一個文件),當出現上述文件描述符耗盡的情況時,釋放占用的描述符,此時就會出現一個空閑描述符,重新調用accept函數后會正常返回,然后再顯示關閉連接,重新打開文件占用空閑描述符
以打電話為例解釋二/三/四次握手
二次握手
A:你好,我是A,你能聽見我說話嗎
B:你好,我能聽見你說話,你能聽見我說話嗎
A:今天跟你談談事情1,balabalalba….
B:你好,我能聽見你說話,你能聽見我說話嗎
A:今天跟你談談事情2,又balabalabala…
B:我tm問你能不能聽見我說話,fuck!
A:今天跟你談談事情3,再balabalabala…
B:…
顯然B無法確定A是否能聽見自己說話,所以會一直詢問。而A已經知道B能聽見自己說話,所以會直接談具體事情,導致無法進行正常交流
三次握手
A:你好,我是A,你能聽見我說話嗎
B:你好,我能聽見你說話,你能聽見我說話嗎
A:我能聽見你說話
B:OK
A:今天跟你談談事情1,balabalabala…
B:噢這個事啊,balabalabala…
A和B都已確定對方能夠聽見自己說話,所以可以進行正常交流
四次握手
A:你好,我是A,你能聽見我說話嗎
B:你好,我能聽見你說話
B:你好,我是B,你能聽見我說話嗎
A:你好,我能聽見你說話
B:OK
A:今天跟你談談事情1,balabalabala…
B:噢這個事啊,balabalabala…
A和B也可以進行正常交流,但是第二三次握手時B完全可以濃縮成”我能聽見你說話,你能聽見我說話嗎”
三次握手抓包分析
下面利用tcpdump命令在linux環境下進行三次握手的抓包分析,通過抓包,可以看到連接過程中一些主要數據的傳輸
在上面的介紹中得知三次握手的過程中會進行如下數據交互(僅考慮序列號,其中A是客戶端,B是服務器)
A->B:SYN同步報文段,帶有起始序列號seq = x
B->A:SYN/ACK同步/確認報文段,帶有起始序列號seq = y以及希望下次接收的序列號ack = x + 1
A->B:ACK確認報文段,對服務器的確認ack = y + 1
首先需要有服務器和客戶端程序,自己敲兩個就行,然后啟動tcpdump命令
- -S表示顯示的序列號是絕對值,而不是相對值
- -i lo指定網絡接口,可以通過ifconfig命令查看接口
- tcp表示只抓取tcp數據包
- port 9999指定抓取端口,這里假設服務器監聽9999端口
隨后運行服務器和客戶端,觀察tcpdump命令輸出
輸出結果分為三行,分別對應每一次握手,可以看到
- 客戶端發送給服務器的SYN同步報文段中包含自己的起始序列號2360165387
- 服務器發送給客戶端的SYN/ACK報文段中包含自己的起始序列號2184124889以及希望下次從客戶端接收的序列號2360165388(可以看到正是第一次握手發送的序列號加一,因為SYN報文段占用了一個序列號)
- 客戶端發送給服務器ACK報文段中包含希望下次從服務器接收的序列號2184124890,可以看到同樣是服務器上次傳送的序列號加一
總結
以上是生活随笔為你收集整理的TCP/IP学习笔记(二)TCP三次握手的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 每天一道LeetCode-----将数值
- 下一篇: TCP/IP学习笔记(三)TCP流量控制