網絡基礎知識(二):TCP

1.一個TCP數據報文格式:
這裏寫圖片描述
1)TCP報頭通常是20字節,不過有選項可以增加報頭長度。由首部長度的4bit可知,最大TCP頭長度可達到60字節。
2)Flag共佔6位,有6個標記,分別是:
URG——緊急指針(16位的緊急指針式緊急數據的偏移量)
ACK——確認序號有效
PSH——接收方儘快將數據提交給應用層
RST——重建連接
SYN——同步序號發起連接
FIN——發送端完成發送任務
3)接收端如何通過ACK校驗數據:如果收到1025~2048字節的報文段校驗和錯,那麼接收方會回覆一個確認序號爲1025的ACK。
4)我們注意到:TCP和UDP的端口號都放在報頭最前面,爲什麼?
因爲:ICMP差錯報文返回的數據中,只能包括IP頭和產生ICMP差錯報文的IP數據報的前8個字節!!!UDP可以放在任意位置,因爲UDP報頭只有8字節;而TCP報頭有20字節,如果放在後面那麼返回的ICMP差錯報文中只有IP而不包含端口信息了。

2.使用tcpdump觀察TCP
使用telnet進行tcp連接,使用tcpdump對產生的tcp數據報進行監控。
a.標識:S爲SYN、F爲FIN、R爲RST、P爲PUSH、.爲以上四個均爲0
b.一個S/P/F的數據報中都包含開始序號、結尾序號和數據長度以及窗口大小,而ack只包含希望收到的序號以及窗口大小。
c.在三次握手的前兩次中,都會互相發送mss以確定最大報文長度。以太網最大mss爲1460(計算方法:以太網MTU爲1500,減去20字節IP頭以及20字節TCP頭)
d.SYN和FIN都佔用一個序號!並且FIN還會發送一個文件結束符(因爲發送FIN意味着發送方發送完畢)

3.TCP爲什麼要有第三次握手
其實正常狀態下,兩次握手可以完全建立連接,但是設想一種場景:
如果client發送完SYN後沒有收到server的ack,client在超時後會重發SYN,而此時這兩個SYN都有可能在網絡中,server端並不知情,每次收到一個SYN就會回覆一個ACK,那麼判斷這個連接是否有效就要落在client的第三次握手上了,如果已經建立了連接,那麼client再收到server的ack時就會將該包丟棄。

4.TCP半關閉
client端完成發送後,即可發送一個FIN(如果只有一個數據報,那麼可以將FIN同數據一同發送),即使受到server的FIN ack也並不影響client的接收和回覆ack,直到server發送FIN,client才進入timewait狀態。

5.TCP狀態變遷圖
這裏寫圖片描述
6.TIME_WAIT狀態(爲什麼要有第四次揮手?)
TCP中有關網絡編程最不容易理解的是它的TIME_WAIT狀態。執行主動關閉的那端進入這種狀態,該端點停留在這種狀態的持續時間是最長分節生命週期(MSL)的兩倍,有時候稱之爲2MSL。 任何TCP實現都必須選擇一個MSL值。RFC1122的建議值是2分鐘,而源自Berkeley的實現傳統上使用的值爲30秒。這意味這TIME_WAIT狀態的延遲在1-4分鐘之間。MSL是IP數據報能在互聯網中生存的最長時間。
許多實現MSL爲30s,IP首部中的TTL爲每個IP數據報規定了生存時間上限:255s或255跳,哪一個先到都會是IP數據報被路由器丟棄。

存在TIME_WATI狀態有兩個理由:
1) 可靠地實現TCP全雙工連接的終止。
2) 允許老的重複分節在網絡中消逝。

第一個理由的解釋如下:假設TCP連接終止的最終的ACK丟失,服務器將重發最終的FIN,因此客戶必需維護狀態信息,以允許它重發最終的ACK。要是不維護狀態信息,它將響應以RST,而服務器則把該分節解釋成一個錯誤。如果TCP打算執行所有必要的工作以徹底終止某個連接上的兩個方向的數據流(即全雙工關閉),那麼它必須正確處理連接終止序列四個分節中任何一個分節的丟失情況。本例子也說明了爲什麼進入TIME_WAIT狀態的是執行主動關閉的那一端:因爲可能不得不重發最終的ACK的是這一段。

要理解存在TIME_WAIT狀態的第二個理由,我們假設在12.106.32.254的端口1500和206.168.112.219的端口21之間有一個TCP連接。我們關閉這個連接後,在以後某個時候又重新建立起相同的IP和端口之間的TCP連接。後一個連接稱爲前一個連接的化身,因爲它的IP地址和端口號都相同。TCP必須防止來自某個連接的老的重複分組在該鏈接已經終止後再現,從而被誤解成屬於同一連接的新化身。爲做到這一點,TCP將不給處於TIME_WAIT狀態的連接啓動新的化身。既然TIME_WAIT狀態持續的時間是2MSL,這就足夠允許某個方向上的分組最多存活MSL秒即被丟棄,另一個方向上的應答最多存活MSL秒也被丟棄。通過實施這個規則,我們能夠保證每當成果建立一個TCP連接時,來自該連接先前化身的老的重複分組都已在網絡中消逝。

所以,當處於TIME_WAIT的主機再次收到FIN時,會回覆一個ACK並對2MSL定時器重新計時。

7.FIN_WAIT_2狀態無限等待
我們知道,當client收到FIN的ack時會變爲FIN_WAIT_2狀態,而只有收到server的FIN時纔會恢復一個ack並進入TIME_WAIT狀態。如果server端一直不發送FIN呢?爲了防止無限等待,如果client要執行的是全關閉,而不是半關閉,那麼會啓動一個定時器,經過10分75秒後超時,直接進入CLOSED狀態。

8.異常釋放連接,發送一個Rst
雙發都不會有多餘的響應,而是直接釋放連接。使用sock的-L0選項發送RST。

9.服務器忙時,TCP如何處理呼入請求?
1)連接隊列:
TCP在內核中維護一個連接隊列,這個隊列的長度由listen()指定。一般都設置爲5,原因:
這個值被稱爲積壓值,它的值對應的是隊列的最大連接數,有公式(最大連接數 = 積壓值*3/2 + 1)。而積壓值得範圍是0到5。由公式可知,最大連接數爲8。
2)應用層只有在三次握手的第三個報文段接收到後纔會知道這個連接。而client回覆最後一個ack時表示成功建立連接,這個ack是可能攜帶數據的,如果此時server應用層還沒有處理這個新的連接,那麼數據就會被TCP放入緩衝隊列中,這也就是TCP滑動窗口的作用了,由於接收方還有數據在緩衝隊列中沒有被應用進程讀取,所以接收方再回復發送方的ack中就會相應的減小win。
3)使用sock模擬連接超時
Sock –O30會讓服務器進程在沒有接收到任何請求時暫停30s。由於應用進程的暫停並不影響內核中TCP的工作,所以TCP中正常進行三次握手,那麼由於應用進程一直沒有處理新的連接,就會在連接隊列中堆積,當隊列滿時,TCP就不會處理傳入的SYN,也不會回送RST。因爲回覆client RST會使client的主動連接失敗並返回,而不處理的結果就是client不斷的超時並重新發送SYN。

另外:由於TCP只有在建立完連接之後纔會通知應用進程,所以應用進程是無法對client的主動連接進行干涉的。Server能做的只是FIN或RST,而無論哪個都是建立在已成功連接的基礎上的。

10.一次DNS查詢要發送多少分組?如果是TCP呢?
一次DNS要有5個查詢,如果是UDP是10個分組,而TCP將會是55個。

11.Nagle算法: 減少了廣域網傳輸的小分組數目。
時延確認技術:回覆的ACK有一個超時計數器,當小於200ms時間內有其他分組要發送,那麼這個ACK就和這個分組合併發送,否則超時後發送ACK。
禁止Nagle算法傳輸速度會變快,但對網絡壓力大!

12.滑動窗口協議:
是流量控制方法。由於無須每發送一個分組就阻塞等待確認,從而加速數據的傳輸。
當接收方回覆ack並win爲0時,表示接受緩衝區已滿,讓發送方等待。而當接收方緩衝區有空間時,會發送與上一次ack相同的序號,並更新win大小(窗口每增加2mss或1/2接收方最大窗口時,發送更新窗口ack)。
1) 窗口左邊沿向右移動——窗口合攏——數據被髮送和確認;
2) 右邊沿向右移動——窗口張開——接收應用進程從接收方緩衝區中讀出數據;
3) 右邊沿向左移動——窗口收縮——不建議使用;
4) 左邊沿向左移動——重複的ACK——發送方丟棄。

13.PUSH標誌
並不是程序員應用層指定的,而是內核自動添加的。如果當前分組發送後,sendbuf爲空,那麼當前的分組就自動帶有PUSH標誌。
例: 發送方要發送8192字節,發送方win(sendbuf)爲4096,接收方win(recvbuf)爲6144,mss爲1024。那麼發送方可以連續發送6個1024的分組,而第四個分組將帶有PUSH標誌。因爲發送完4096個字節後,發送方會清空sendbuf然後填充下一次4096字節。

14.連接的理想穩定狀態: 發送方同時send和recv,路徑上總是具有相同數目的ack。
帶寬時延乘積 = 帶寬*RTT

15.緊急方式
URG標誌位置1,16位的緊急指針作爲偏移量與序號相加,計算出緊急數據最後一個字節的序號。只有這個字節被處理完畢纔會從緊急狀態變爲正常狀態。
緊急方式作用:當發送方無法發送數據(接收方通知的win爲0)時,發送方會發送URG標誌和緊急指針,通知接收方應用進程儘快從TCP接受緩衝區中讀出數據。

16.對每個連接,TCP管理4個定時器:
1) 重傳定時器:每次超時重傳的時間都是上一次的2倍,直至64s,最終發送RST。
2) 堅持定時器:當發送方由於接收方的通告窗口爲0而阻塞時,如果接收方發送的窗口更新ack丟失,那麼就會死鎖。爲了防止窗口更新死鎖,堅持定時器使發送方週期性查詢,以發現是否有窗口更新,堅持時間每次*2,直至60s。
3) 保活定時器:如果連接上2個小時沒有動作,server就向client發送keepalive分組。
4) 2MSL定時器:測量TIME_WAIT狀態的時間。

17.慢啓動算法
慢啓動增加了TCP另一個窗口:擁塞窗口(cwnd)。
擁塞窗口時發送方的流量控制、通告窗口時接收方的流量控制。發送方取擁塞窗口和通告窗口的最小值作爲發送上限。
擁塞窗口初始化爲1個mss大小,之後每接收到一個ack就增加一個mss大小,所以從宏觀上看,慢啓動是指數增長的,但是我們通過tcpdump觀察時時一個一個mss增長的(tcpdump每收到一個分組都顯示)。

18.擁塞避免算法
作用:處理丟失分組。
和慢啓動是不同的算法,但經常結合使用。共同維護兩個變量:
擁塞窗口cwnd和慢啓動門限ssthresh。
工作過程:
1) 初始化cwnd爲1個mss大小,ssthresh爲65535個字節。
2) 當擁塞發生時(重傳定時器超時或連續收到三個重複的ack),ssthresh被設爲當前窗口的一半(當前窗口爲cwnd和通告窗口的最小值),但最小爲2個mss;但如果是超時引起的擁塞,則直接將窗口設爲1mss,即直接變爲慢啓動!
3) 發送方每收到一個ack就將cwnd加1,直到cwnd大於ssthresh。所以,在cwnd小於等於ssthresh時,是慢啓動方式,指數增長;而大於ssthresh後使用擁塞避免增長方式:每收到一個ack,將cwnd加1/cwnd大小,即變爲線性增長,不管在當前RTT中受到多少ack每次最多允許cwnd加1。

19.快速重傳和快速恢復算法
快速重傳:連續收到3個重複的ack就重傳丟失的數據報,無須等待重傳定時器溢出。
快速恢復:快速重傳後不執行慢啓動,而是執行擁塞避免算法。
工作過程:
1) 當收到三個重複的ack時,將ssthresh設爲cwnd的一半(最小2個mss),將cwnd設爲ssthresh加3個mss大小。
2) 使用擁塞避免的方式,而不是慢啓動。即快速恢復。
3) 快速重傳後的連接,在發送端再接收到重複ack的時候允許cwnd加1。而快速重傳之前是不允許的。

爲什麼快速重傳後使用擁塞避免,而不是慢啓動?
接收方回覆連續重複的ack,說明除了丟失的分組外,其餘的分組都是正常發送並存入接收方的緩衝區的,所以當前兩段之間仍然有流動的數據,此時如果執行慢啓動,會使數據流突然減小,不是我們想看到的。

爲什麼快速重傳後,再接收到重複ack就允許cwnd+1了?
其實接收方回覆重複的ack,只是說明丟失了該分組,並不影響整個連接的流量,所以執行快速恢復算法時允許cwnd+1,而在快速重傳算法觸發前快速恢復算法也不會觸發,所以是不允許cwnd+1的。

什麼情況下會產生重複ack?
1) 丟失該分組
2) 由於網絡時延導致的接收方收到的分組順序發生改變。例如:
發送方發送:1、2、3、4
接收方收到:1、3、2、4時,就會產生一個序號爲2的重複ack;而如果接收方收到:1、3、4、2時,就會產生序號爲2的兩個重複ack。
注意:3和4兩個分組都被接收方緩存在recvbuf中,直到收到序號爲2的分組,一起回送序號爲5的ack並通知應用進程將數據讀取出去。

只有重傳纔會改變ssthresh值,而重傳有兩種方式: 超時重傳和快速重傳。

20.TCP遇到的常見ICMP差錯
1) 源站抑制:引發超時重傳,cwnd置1,觸發慢啓動,但ssthresh不會產生變化。
2) 主機不可達:忽略。堅持重傳。直至64s間隔重傳後,發送RST。
3) 網絡不可達:忽略。堅持重傳。同上。

21.TCP的重新分組
TCP超時重傳時,不一定發送相同的分組,可以將較小的分組合並後發送。因爲TCP是流傳輸,依靠的是字節序號,而不是分組序號。

22.TCP的keepalive定時器:
如果一個連接在2小時內無動作,server會發送該分組。Sock –K是保活選項。
Client有以下4中狀態:
1) Client主機正常運行,server可達。
2) client主機崩潰,已經關閉或正在重啓。Server會連續發送10個keepalive探查,間隔75s。
3) client主機崩潰,並已經重啓。Server會收到一個RST相應,終止連接。
4) client主機正常運行,但server不可達。與2)相同。

我們可以修改keepalive定時器的2小時變量,但由於該功能是TCP內部工作的,是內核態的,如果當前應用程序修改了定時器,其他的所有的使用TCP服務的程序也會收到影響!

23.TCP的keepalive選項的優缺點
優點:1)比應用層keepalive報文佔用更少的帶寬(該報文不含任何數據);2)只有在空閒時纔會發送探查報文。
缺點:報文的探測時間不能隨意修改(由於是內核態的,影響其他應用)。

24.TCP路徑MTU發現機制
建立連接時,TCP使用client和對端的MSS中的最小值作爲起始報文段大小,如果對端沒有聲明,默認mss爲536。(注意這裏的對端並不一定是server,而是路徑上的下一個節點)

具有DF選項的數據報不能分片,如果分片,產生ICMP報文差錯。

注意:分組大使帶寬利用率變大,但並不是分組越大就越好。由於分組越小,數據報也越多,相對而言,鏈路的空閒時間就少。(詳見TCP/IP詳解P259)

25.TCP在長肥管道中的問題
1) 窗口大小限制:TCP中窗口大小爲16bit,所以最大65535。
2) 長肥管道中分組丟失是吞吐量急劇減少。
3) TCP對每個窗口的RTT只進行一次測量。
4) 序號迴繞問題:32bit的無符號序號,最多2的32次方,即40億個。而MSL,即最大報文生存時間內,如果序號發生迴繞,那麼就廢了啊!!!我們知道TTL最大可以達到255s,而一個千兆比網絡(1000Mb/s)中34s就會發生迴繞!!!(4G*8/1000M=34s)

解決:
1) 窗口擴大選項可以擴大14bit,從而可以使窗口變爲2的30次冪大小。
2) 時間戳選項可以解決RTT問題。
3) PAWS算法:防止迴繞的序號。

26.基於TCP的事物協議:T/TCP
TCP爲實現事物需要進行兩個改動:避免三次握手、縮短TIME_WAIT狀態時間。
使用加速打開避免三次握手方法:
Server爲每個client維護一個32bit的計數值CC,如果收到的CC值大於緩存的,說明是SYN是新的,可以直接接受數據;如果收到的CC值小於緩存的或沒有保存該client的CC值,那麼就進行三次握手。這個方法的缺點就是要付出維護每個client的32bit數的代價。
將TIME_WAIT時延設爲8倍的重傳超時值RTO。

通過上述修改,最小的事物序列只包含三個數據報(TCP是11個:3+4+4=11):
1) Client: SYN、數據、FIN、CC;
2) Server: SYN、FIN的ack(由於TCP確認是積累的,所以這個ack包含了對SYN、數據的確認)、FIN、CC以及客戶CC的CCecho;
3) Client: FIN的ack(包含了SYN的ack)

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