首先聲明:TCP分片應該稱為TCP分段
TCP/IP詳解--TCP的分段和IP的分片
分組可以發生在運輸層和網絡層,運輸層中的TCP會分段,網絡層中的IP會分片。IP層的分片更多的是為運輸層的UDP服務的,由於TCP自己會避免IP的分片,所以使用TCP傳輸在IP層都不會發生分片的現象。
我們在學習TCP/IP協議時都知道,TCP報文段如果很長的話,會在發送時發生分段,在接受時進行重組, 同樣IP數據報在長度超過一定值時也會發生分片,在接收端再將分片重組。
我們先來看兩個與TCP報文段分段和IP數據報分片密切相關的概念。
MTU(最大傳輸單元)
MTU前面已經說過了,是鏈路層中的網絡對數據幀的一個限制,依然以以太網為例,MTU為1500個字節。一個IP數據報在以太網中傳輸,如果它的長度大於該MTU值,就要進行分片傳輸,使得每片數據報的長度小於MTU。分片傳輸的IP數據報不一定按序到達,但IP首部中的信息能讓這些數據報片按序組裝 (標識 標志 偏移等信息進行重組合 卷2 有講) 。 IP數據報的分片與重組是在網絡層進完成的。
MSS(最大分段大小)
MSS是TCP里的一個概念(首部的選項字段中)。MSS是TCP數據包每次能夠傳輸的最大數據分段,TCP報文段的長度大於MSS時,要進行分段傳輸。TCP協議在建立連接的時候通常要協商雙方的MSS值,每一方都有用於通告它期望接收的MSS選項(MSS選項只出現在SYN報文段中,即TCP三次握手的前兩次)。MSS的值一般為MTU值減去兩個首部大小(需要減去IP數據包包頭的大小20Bytes和TCP數據段的包頭20Bytes)所以如果用鏈路層以太網,MSS的值往往為1460。 而Internet上標准的MTU(最小的MTU,鏈路層網絡為x2.5時)為576,那么如果不設置,則MSS的默認值就為536個字節。很多時候,MSS的值最好取512的倍數。TCP報文段的分段與重組是在運輸層完成的。
到了這里有一個問題自然就明了了,TCP分段的原因是MSS,IP分片的原因是MTU,由於一直有MSS<=MTU,很明顯,分段后的每一段TCP報文段再加上IP首部后的長度不可能超過MTU,因此也就不需要在網絡層進行IP分片了。因此TCP報文段很少會發生IP分片的情況。
再來看UDP數據報,由於UDP數據報不會自己進行分段,因此當長度超過了MTU時,會在網絡層進行IP分片。同樣,ICMP(在網絡層中)同樣會出現IP分片情況。
在TCP/IP分層中,數據鏈路層用MTU(Maximum Transmission Unit,最大傳輸單元)來限制所能傳輸的數據包大小,MTU是指一次傳送的數據最大長度,不包括數據鏈路層數據幀的幀頭,如以太網的MTU為1500字節,實際上數據幀的最大長度為1518 = 6+6+2+4+1500 字節,其中以太網數據幀的幀頭為6+6+2字節。
當發送的IP數據報的大小超過了MTU時,IP層就需要對數據進行分片,否則數據將無法發送成功。
分片傳輸的IP數據報不一定按序到達,但IP首部中的信息能讓這些數據報片按序組裝。IP數據報的分片與重組是在網絡層進完成的。
區別:
1;========== TCP分段產生原因是MSS.(最大分段大小)
2.IP分片由網絡層完成,也在網絡層進行重組; TCP分段是在傳輸層完成,並在傳輸層進行重組. //透明性
3. 到了這里有一個問題自然就明了了,TCP分段的原因是MSS,IP分片的原因是MTU,由於一直有MSS<=MTU,很明顯,分段后的每一段TCP報文段再加上IP首部后的長度不可能超過MTU,因此也就不需要在網絡層進行IP分片了。因此TCP報文段很少會發生IP分片的情況。 若數據過大,只會在傳輸層進行數據分段,到了IP層就不用分片。
4 而我們常提到的 IP分片是由於UDP傳輸協議造成的,因為UDP傳輸協議並未限定傳輸數據報的大小。
——————————————————————————————————————————————————————
總結:UDP不會分段,就由IP來分片。 TCP會分段,當然就不用IP來分片了!
區分TCP分段和IP分片,了解它們工作在不同的層
為什么要避免UDP數據報在IP層分片呢?!!!! why 如下:
在網絡編程中,我們要避免出現IP分片,那么為什么要避免呢?
原因是IP層是沒有超時重傳機制的,如果IP層對一個數據包進行了分片,只要有一個分片丟失了,只能依賴於傳輸層進行重傳,結果是所有的分片都要重傳一遍,這個代價有點大。
由此可見,IP分片會大大降低傳輸層傳送數據的成功率,所以我們要避免IP分片。
對於UDP包,我們需要在應用層去限制每個包的大小,一般不要超過1472字節,即以太網MTU(1500—UDP首部(8)—IP首部(20)。
對於TCP數據,應用層就不需要考慮這個問題了,因為傳輸層已經幫我們做了。在建立連接的三次握手的過程中,連接雙方會相互通告MSS(Maximum Segment Size,最大報文段長度),MSS一般是MTU—IP首部(20)—TCP首部(20),每次發送的TCP數據都不會超過雙方MSS的最小值,所以就保證了IP數據報不會超過MTU,避免了IP分片。
udp中一個包大小究竟為多大合適
在進行UDP編程的時候,我們最容易想到的問題就是,一次發送多少bytes好?
當然,這個沒有唯一答案,相對於不同的系統,不同的要求,其得到的答案是不一樣的,我這里僅對像ICQ一類的發送聊天消息的情況作分析,對於其他情況,你或許也能得到一點幫助。
結論1:局域網環境下,建議將UDP數據控制在1472字節以下
以太網(Ethernet)數據幀的長度必須在46-1500字節之間,這是由以太網的物理特性決定的,這個1500字節被稱為鏈路層的MTU(最大傳輸單元)。
但這並不是指鏈路層的長度被限制在1500字節,其實這個MTU指的是鏈路層的數據區,並不包括鏈路層的首部和尾部的18個字節。
所以,事實上這個1500字節就是網絡層IP數據報的長度限制。因為IP數據報的首部為20字節,所以IP數據報的數據區長度最大為1480字節。而這個1480字節就是用來放TCP傳來的TCP報文段或UDP傳來的UDP數據報的。
又因為UDP數據報的首部8字節,所以UDP數據報的數據區最大長度為1472字節。這個1472字節就是我們可以使用的字節數。
當我們發送的UDP數據大於1472的時候會怎樣呢? 這也就是說IP數據報大於1500字節,大於MTU,這個時候發送方IP層就需要分片(fragmentation)。把數據報分成若干片,使每一片都小於MTU,而接收方IP層則需要進行數據報的重組。這樣就會多做許多事情,而更嚴重的是,由於UDP的特性,當某一片數據傳送中丟失時,接收方無法重組數據報,將導致丟棄整個UDP數據報。
因此,在普通的局域網環境下,我建議將UDP的數據控制在1472字節以下為好。
結論2:Internet編程時,建議將UDP數據控制在548字節以下
進行Internet編程時則不同,因為Internet上的路由器可能會將MTU設為不同的值。如果我們假定MTU為1500來發送數據,而途經的某個網絡的MTU值小於1500字節,那么系統將會使用一系列的機制來調整MTU值,使數據報能夠順利到達目的地,這樣就會做許多不必要的操作。
鑒於Internet上的標准MTU值為576字節,所以我建議在進行Internet的UDP編程時, 最好將UDP的數據長度控件在548字節(576-8-20)以內。
1、三次握手
(1)三次握手的詳述
首先Client端發送連接請求報文,Server段接受連接后回復ACK報文,並為這次連接分配資源。Client端接收到ACK報文后也向Server段發生ACK報文,並分配資源,這樣TCP連接就建立了。
最初兩端的TCP進程都處於CLOSED關閉狀態,A主動打開連接,而B被動打開連接。(A、B關閉狀態CLOSED——B收聽狀態LISTEN——A同步已發送狀態SYN-SENT——B同步收到狀態SYN-RCVD——A、B連接已建立狀態ESTABLISHED)
- B的TCP服務器進程先創建傳輸控制塊TCB,准備接受客戶進程的連接請求。然后服務器進程就處於LISTEN(收聽)狀態,等待客戶的連接請求。若有,則作出響應。
- 1)第一次握手:A的TCP客戶進程也是首先創建傳輸控制塊TCB,然后向B發出連接請求報文段,(首部的同步位SYN=1,初始序號seq=x),(SYN=1的報文段不能攜帶數據)但要消耗掉一個序號,此時TCP客戶進程進入SYN-SENT(同步已發送)狀態。
- 2)第二次握手:B收到連接請求報文段后,如同意建立連接,則向A發送確認,在確認報文段中(SYN=1,ACK=1,確認號ack=x+1,初始序號seq=y),測試TCP服務器進程進入SYN-RCVD(同步收到)狀態;
- 3)第三次握手:TCP客戶進程收到B的確認后,要向B給出確認報文段(ACK=1,確認號ack=y+1,序號seq=x+1)(初始為seq=x,第二個報文段所以要+1),ACK報文段可以攜帶數據,不攜帶數據則不消耗序號。TCP連接已經建立,A進入ESTABLISHED(已建立連接)。
- 當B收到A的確認后,也進入ESTABLISHED狀態。
(2)總結三次握手過程:
- 第一次握手:起初兩端都處於CLOSED關閉狀態,Client將標志位SYN置為1,隨機產生一個值seq=x,並將該數據包發送給Server,Client進入SYN-SENT狀態,等待Server確認;
- 第二次握手:Server收到數據包后由標志位SYN=1得知Client請求建立連接,Server將標志位SYN和ACK都置為1,ack=x+1,隨機產生一個值seq=y,並將該數據包發送給Client以確認連接請求,Server進入SYN-RCVD狀態,此時操作系統為該TCP連接分配TCP緩存和變量;
- 第三次握手:Client收到確認后,檢查ack是否為x+1,ACK是否為1,如果正確則將標志位ACK置為1,ack=y+1,並且此時操作系統為該TCP連接分配TCP緩存和變量,並將該數據包發送給Server,Server檢查ack是否為y+1,ACK是否為1,如果正確則連接建立成功,Client和Server進入ESTABLISHED狀態,完成三次握手,隨后Client和Server就可以開始傳輸數據。
起初A和B都處於CLOSED狀態——B創建TCB,處於LISTEN狀態,等待A請求——A創建TCB,發送連接請求(SYN=1,seq=x),進入SYN-SENT狀態——B收到連接請求,向A發送確認(SYN=ACK=1,確認號ack=x+1,初始序號seq=y),進入SYN-RCVD狀態——A收到B的確認后,給B發出確認(ACK=1,ack=y+1,seq=x+1),A進入ESTABLISHED狀態——B收到A的確認后,進入ESTABLISHED狀態。
TCB傳輸控制塊Transmission Control Block,存儲每一個連接中的重要信息,如TCP連接表,到發送和接收緩存的指針,到重傳隊列的指針,當前的發送和接收序號。
(3)為什么A還要發送一次確認呢?可以二次握手嗎?
答:主要為了防止已失效的連接請求報文段突然又傳送到了B,因而產生錯誤。
如A發出連接請求,但因連接請求報文丟失而未收到確認,於是A再重傳一次連接請求。后來收到了確認,建立了連接。數據傳輸完畢后,就釋放了連接,A發出了兩個連接請求報文段,其中第一個丟失,第二個到達了B,但是第一個丟失的報文段只是在某些網絡結點長時間滯留了,延誤到連接釋放以后的某個時間才到達B, 此時B誤認為A又發出一次新的連接請求,於是就向A發出確認報文段,同意建立連接,不采用三次握手,只要B發出確認,就建立新的連接了,此時A不理睬B的確認且不發送數據,則B一致等待A發送數據,浪費資源。
下面才是標准答案!!!! 上面謝希任的書 講解有誤
為了實現可靠數據傳輸, TCP 協議的通信雙方, 都必須維護一個序列號, 以標識發送出去的數據包中, 哪些是已經被對方收到的。 三次握手的過程即是通信雙方相互告知序列號起始值, 並確認對方已經收到了序列號起始值的必經步驟
如果只是兩次握手, 至多只有連接發起方的起始序列號能被確認, 另一方選擇的序列號則得不到確認
(4)Server端易受到SYN攻擊?
服務器端的資源分配是在二次握手時分配的,而客戶端的資源是在完成三次握手時分配的,所以服務器容易受到SYN洪泛攻擊,SYN攻擊就是Client在短時間內偽造大量不存在的IP地址,並向Server不斷地發送SYN包,Server則回復確認包,並等待Client確認,由於源地址不存在,因此Server需要不斷重發直至超時,這些偽造的SYN包將長時間占用未連接隊列,導致正常的SYN請求因為隊列滿而被丟棄,從而引起網絡擁塞甚至系統癱瘓。
防范SYN攻擊措施:降低主機的等待時間使主機盡快的釋放半連接的占用,短時間受到某IP的重復SYN則丟棄后續請求。
2、四次揮手
(1)四次揮手的詳述
假設Client端發起中斷連接請求,也就是發送FIN報文。Server端接到FIN報文后,意思是說"我Client端沒有數據要發給你了",但是如果你還有數據沒有發送完成,則不必急着關閉Socket,可以繼續發送數據。所以你先發送ACK,"告訴Client端,你的請求我收到了,但是我還沒准備好,請繼續你等我的消息"。這個時候Client端就進入FIN_WAIT狀態,繼續等待Server端的FIN報文。當Server端確定數據已發送完成,則向Client端發送FIN報文,"告訴Client端,好了,我這邊數據發完了,准備好關閉連接了"。Client端收到FIN報文后,"就知道可以關閉連接了,但是他還是不相信網絡,怕Server端不知道要關閉,所以發送ACK后進入TIME_WAIT狀態,如果Server端沒有收到ACK則可以重傳。“,Server端收到ACK后,"就知道可以斷開連接了"。Client端等待了2MSL后依然沒有收到回復,則證明Server端已正常關閉,那好,我Client端也可以關閉連接了。Ok,TCP連接就這樣關閉了!
數據傳輸結束后,通信的雙方都可釋放連接,A和B都處於ESTABLISHED狀態。(A、B連接建立狀態ESTABLISHED——A終止等待1狀態FIN-WAIT-1——B關閉等待狀態CLOSE-WAIT——A終止等待2狀態FIN-WAIT-2——B最后確認狀態LAST-ACK——A時間等待狀態TIME-WAIT——B、A關閉狀態CLOSED)
- 1)A的應用進程先向其TCP發出連接釋放報文段(FIN=1,序號seq=u),並停止再發送數據,主動關閉TCP連接,進入FIN-WAIT-1(終止等待1)狀態,等待B的確認。
- 2)B收到連接釋放報文段后即發出確認報文段,(ACK=1,確認號ack=u+1,序號seq=v),B進入CLOSE-WAIT(關閉等待)狀態,此時的TCP處於半關閉狀態,A到B的連接釋放。
- 3)A收到B的確認后,進入FIN-WAIT-2(終止等待2)狀態,等待B發出的連接釋放報文段。
- 4)B沒有要向A發出的數據,B發出連接釋放報文段(FIN=1,ACK=1,序號seq=w,確認號ack=u+1),B進入LAST-ACK(最后確認)狀態,等待A的確認。
- 5)A收到B的連接釋放報文段后,對此發出確認報文段(ACK=1,seq=u+1,ack=w+1),A進入TIME-WAIT(時間等待)狀態。此時TCP未釋放掉,需要經過時間等待計時器設置的時間2MSL后,A才進入CLOSED狀態。
(2)總結四次揮手過程:
起初A和B處於ESTABLISHED狀態——A發出連接釋放報文段並處於FIN-WAIT-1狀態——B發出確認報文段且進入CLOSE-WAIT狀態——A收到確認后,進入FIN-WAIT-2狀態,等待B的連接釋放報文段——B沒有要向A發出的數據,B發出連接釋放報文段且進入LAST-ACK狀態——A發出確認報文段且進入TIME-WAIT狀態——B收到確認報文段后進入CLOSED狀態——A經過等待計時器時間2MSL后,進入CLOSED狀態。
(3)為什么A在TIME-WAIT狀態必須等待2MSL的時間?
MSL最長報文段壽命Maximum Segment Lifetime,MSL=2
答: 兩個理由:1)保證A發送的最后一個ACK報文段能夠到達B。2)防止“已失效的連接請求報文段”出現在本連接中。
- 1)這個ACK報文段有可能丟失,使得處於LAST-ACK狀態的B收不到對已發送的FIN+ACK報文段的確認,B超時重傳FIN+ACK報文段,而A能在2MSL時間內收到這個重傳的FIN+ACK報文段,接着A重傳一次確認,重新啟動2MSL計時器,最后A和B都進入到CLOSED狀態,若A在TIME-WAIT狀態不等待一段時間,而是發送完ACK報文段后立即釋放連接,則無法收到B重傳的FIN+ACK報文段,所以不會再發送一次確認報文段,則B無法正常進入到CLOSED狀態。
- 2)A在發送完最后一個ACK報文段后,再經過2MSL,就可以使本連接持續的時間內所產生的所有報文段都從網絡中消失,使下一個新的連接中不會出現這種舊的連接請求報文段。
(4)為什么連接的時候是三次握手,關閉的時候卻是四次握手?
答:因為當Server端收到Client端的SYN連接請求報文后,可以直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連接時,當Server端收到FIN報文時,很可能並不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了"。只有等到我Server端所有的報文都發送完了,我才能發送FIN報文,因此不能一起發送。故需要四步握手。
(5)為什么TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?
答:雖然按道理,四個報文都發送完畢,我們可以直接進入CLOSE狀態了,但是我們必須假象網絡是不可靠的,有可以最后一個ACK丟失。所以TIME_WAIT狀態就是用來重發可能丟失的ACK報文。
TCP的最大報文段長度
上面介紹了TCP連接的建立和釋放過程,下面介紹一下TCP的最大報文段長度。
最大報文段長度(MSS)表示TCP傳往另一端的最大塊數據的長度。當一個連接建立時,連接的雙方都要通告各自的MSS。一般來說,MSS越大越好,因為報文段越大允許每個報文段傳送的數據就越多,相對IP和TCP首部有更高的網絡利用率。
MSS選項只能出現在SYN報文段中,所以只能在SYN=1的幀中才會有MSS選項說明報文的最大段長度。
---------------------
關於TCP的內容還有很多,這里不再詳細說明,但是需要知道,TCP連接的建立和釋放還有幾種比較特殊的情況,
同時打開(SYN)建立連接,同時關閉或半關閉來釋放連接的情況都是存在的,還有一些TCP的可選字段,這里都不再講了,具體可以參考:TCP/IP 詳解卷1。