《TCP/IP詳解卷2:實現》筆記--TCP的輸入

當收到的數據報的協議字段指明這是一個TCP報文段時,ipintr(通過協議協議轉換表中的pr_input函數)會調用tcp_input

進行處理,tcp_inut在軟件中斷一級執行。

函數非常長,我們將分兩張討論,下圖列出了tcp_input中的處理框架。本章將結束對RST報文段處理的講解,下一章開始

介紹ACK報文段的處理。

頭幾個步驟是非常典型的:對輸入報文段做有效性驗證(檢驗和、長度等),以及尋找連接的PCB。儘管後面還有大量的

代碼,但通過“首部預測”,算法卻有可能完全跳過後續的邏輯。首部預測算法是基於這樣的假定,一般情況下,報文段既

不會丟失,次序也不會錯誤,因此,對於給定連接,TCP總能猜到下一個接收報文段的內容。如果算法起作用,函數直接

返回,這是tcp_input中最快的一條執行路徑。


1.預處理

該部分介紹對收到的TCP報文段進行於預處理。處理的大概流程如下:

1.從第一個mbuf中獲取IP和TCP首部。

2.驗證TCP的檢驗和。

3.驗證TCP偏移字段。

4.把IP和TCP首部及選項放入第一個mbuf。

5.快速處理時間戳選項。

6.保存輸入標誌,把字段轉換成主機字節序。

7.尋找Internet PCB。

8.如果沒有找到PCB,則丟棄報文,併發送RST作爲響應。

9.如果TCP控制塊存在,但連接狀態爲closed,說明插口已創建,且得到了本地地址和本地端口號,但還未調用connect或

listen。報文段被丟棄,且不發送任何響應。

10.不改變通告窗口大小。

11.如果選定了插口調試選項,則保存連接狀態及IP和TCP首部。

12.如果監聽插口收到了報文段,則創建新的插口。

13.計算窗口縮放因子。

14.復位空閒時間和保活定時器。

15.如果不處於監聽狀態,處理TCP選項。


2.首部預測

首部預測算法通過處理兩種常見現象,簡化單向數據傳輸的實現。

1.如果TCP發送數據,連接上等待接收的下一個報文段是對已發送數據的ACK。

2.如果TCP接收數據,連接上等待的下一個報文段時順序到達的數據報文段。


3.TCP輸入:緩慢的執行路徑

下面介紹首部預測失敗時的處理代碼,tcp_input中較慢的一條執行路徑。

1.丟棄IP和TCP首部,包括TCP選項。

2.計算接收窗口。

因爲函數後面的代碼必須確定通告窗口中能放入多少數據,所以現在必須計算通告窗口的大小。落在通告窗口之外的接收

數據被丟棄;落在窗口左側的數據是已接收並確認過的數據,落在窗口右側的數據時暫時不允許對端發送的數據。


4.完成被動打開或主動打開

如果連接狀態等於LISTEN或者SYN_SENT,則執行本節的處理。連接處於這兩個狀態時,等待接收的報文段爲SYN,任何

其他報文將被丟棄。

4.1.完成被動打開

連接狀態等於LISTEN時,執行以下處理:
1.丟棄RST、ACK或非SYN。
2.如果是廣播報文段或多播報文段,則丟棄它。
3.爲客戶端的IP地址和端口號分配mbuf。
4.設定PCB中的本地地址。
5.填充PCB中的對端地址。
6.分配並初始化IP和TCP首部模板。
7.處理所有的TCP選項。
8.初始化ISS。
9.初始化控制塊中的序號變量。
10.確認SYN並更新狀態。

4.2.完成主動打開

1.驗證收到的ACK
2.處理並丟棄RST報文段。
3.判斷收到的SYN標誌是否置位。
4.處理ACK。
5.關閉連接建立定時器。
6.初始化接收序號。
7.連接建立。
8.查看窗口大小選項。
9.嚮應用進程提交隊列中的數據。
10.更新RTT估計器值。
11.處理同時打開。
12.丟棄落在接收窗口外的數據。
13.強制更新窗口變量。

5.PAWS:防止序號迴繞

接下來處理可能出現的序號迴繞。
1.基本PAWS測試
PAWS算法基於這樣的假定:
對於高速連接,32bit時間戳值迴繞的速度遠小於32bit序號迴繞的速度。即使是最高的失蹤計數器更新頻率(每毫秒加1),
時間戳的符號位也要24天才會迴繞一次。而在千兆網絡中,序號可能17秒就回繞一次。因此,如果報文段時間戳小於從同
一個連接接收的最近一次的時間戳,說明是個重複報文段,應該被丟棄(還需進行後續的時間戳過期測試)。儘管因爲
序號已過時,tcp_input也可將其丟棄,但PAWS算法能夠有效地處理序號迴繞速率很高的高速網。
注意,PAWS算法是對稱的:它不僅丟棄重複的數據報文段,也丟棄重複的ACK。PAWS處理所有收到的報文段。
2.檢查過期的時間戳。
3.丟棄重複報文段

6.裁剪報文段使數據在窗口內

本節討論如何調整收到的報文段,確保它只攜帶能夠放入接收窗口內的數據:
丟棄接收報文段起始處的重複數據。
從報文段尾部起,丟棄超出接收窗口的數據。
從而剩下可放入接收窗口的新數據,用於判斷報文段起始處是否存在重複數據。
1.查看報文段前部是否存在重複數據。
2.丟棄重複SYN.
3.判斷報文段數據是否完全重複。
4.判斷重複FIN。
5.生成重複ACK。
6.處理同時打開或半連接。
7.收到部分重複報文段時,更新統計值。
8.刪除重複數據,更新緊急指針。
9.計算落在通告窗口右側的字節數。
10.如果連接處於TIME_WAIT狀態,查看有無新的連接請求。
11.判斷是否爲窗口探測報文段。
12.丟棄完全落在窗口以外的其他報文段。
13.處理攜帶部分有效數據的報文段。

7.自連接和同時打開

應用進程創建一個插口,並通過下列系統調用建立自連接:socket,bind半丁到一個本地端口,之後connect試圖與同一
本地地址和同一端口號建立連接,如果connect成功,則插口已建立了與自己的連接:向這個插口寫入的所有數據,都可以
在同一插口上讀出。這有點類似於全雙工的管道,但只有一個,而非兩個標識符。儘管很少有應用進程會這樣做,但實際
上它是一種特殊的同時打開,兩者的狀態變遷圖相同。

8.記錄時間戳

下面給出了tcp_input的處理收到的時間戳選項。

如果收到的報文段中帶有時間戳,時間戳值保存在變量中。


9.RST處理

下面給出處理RST標誌的switch語句,取決於當前的連接狀態。

1.SYN_RCVD狀態下,插口差錯代碼設定爲ECONNREFUSED,關閉插口。

2.如果在ESTABLISHED、FIN_WAIT_1、FIN_WAIT_2或CLOSE_WAIT狀態收到RST,則返回差錯代碼ECOORESET。

3.如果狀態爲CLOSING、LAST_ACK或TIME_WAIT,由於應用進程已關閉插口,無需返回差錯代碼。

4.如果SYN標誌依舊置位,說明出現了差錯,連接被丟棄,返回代碼ECONNRESET。

5.如果ACK標誌未置位,報文被丟棄。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章