TCP/IP基礎知識總結

此文屬於轉載
先要看TCP/IP協議,涉及到四層:鏈路層,網絡層,傳輸層,應用層。   
其中以太網(Ethernet)的數據幀在鏈路層   
IP包在網絡層   
TCP或UDP包在傳輸層   
TCP或UDP中的數據(Data)在應用層   
它們的關係是 數據幀{IP包{TCP或UDP包{Data}}}   
---------------------------------------------------------------------------------
在應用程序中我們用到的Data的長度最大是多少,直接取決於底層的限制。   
我們從下到上分析一下:   
1.在鏈路層,由以太網的物理特性決定了數據幀的長度爲(46+18)-(1500+18),其中的18是數據幀的頭和尾,也就是說數據幀的內容最大爲1500(不包括幀頭和幀尾),即MTU(Maximum Transmission Unit)爲1500;  
2.在網絡層,因爲IP包的首部要佔用20字節,所以這的MTU爲1500-20=1480; 
3.在傳輸層,對於UDP包的首部要佔用8字節,所以這的MTU爲1480-8=1472;   
所以,在應用層,你的Data最大長度爲1472。 (當我們的UDP包中的數據多於MTU(1472)時,發送方的IP層需要分片fragmentation進行傳輸,而在接收方IP層則需要進行數據報重組,由於UDP是不可靠的傳輸協議,如果分片丟失導致重組失敗,將導致UDP數據包被丟棄)。   
從上面的分析來看,在普通的局域網環境下,UDP的數據最大爲1472字節最好(避免分片重組)。   
但在網絡編程中,Internet中的路由器可能有設置成不同的值(小於默認值),Internet上的標準MTU值爲576,所以Internet的UDP編程時數據長度最好在576-20-8=548字節以內。
---------------------------------------------------------------------------------  
MTU對我們的UDP編程很重要,那如何查看路由的MTU值呢?   
對於windows OS: ping -f -l   如:ping -f -l 1472 192.168.0.1   
如果提示:Packets needs to be fragmented but DF set.   則表明MTU小於1500,不斷改小data_length值,可以最終測算出gateway的MTU值;   
對於linux OS: ping -c -M do -s   如: ping -c 1 -M do -s 1472 192.168.0.1   
如果提示 Frag needed and DF set……   則表明MTU小於1500,可以再測以推算gateway的MTU。
--------------------------------------------------------------------------------- 
IP數據包的最大長度是64K字節(65535),因爲在IP包頭中用2個字節描述報文長度,2個字節所能表達的最大數字就是65535。 
    
由於IP協議提供爲上層協議分割和重組報文的功能,因此傳輸層協議的數據包長度原則上來說沒有限制。實際上限制還是有的,因爲IP包的標識字段終究不可能無限長,按照IPv4,好像上限應該是4G(64K*64K)。依靠這種機制,TCP包頭中就沒有“包長度”字段,而完全依靠IP層去處理分幀。這就是爲什麼TCP常常被稱作一種“流協議”的原因,開發者在使用TCP服務的時候,不必去關心數據包的大小,只需講SOCKET看作一條數據流的入口,往裏面放數據就是了,TCP協議本身會進行擁塞/流量控制。 
    
UDP則與TCP不同,UDP包頭內有總長度字段,同樣爲兩個字節,因此UDP數據包的總長度被限制爲65535,這樣恰好可以放進一個IP包內,使得UDP/IP協議棧的實現非常簡單和高效。65535再減去UDP頭本身所佔據的8個字節,UDP服務中的最大有效載荷長度僅爲65527。這個值也就是你在調用getsockopt()時指定SO_MAX_MSG_SIZE所得到返回值,任何使用SOCK_DGRAM屬性的socket,一次send的數據都不能超過這個值,否則必然得到一個錯誤。 
    
那麼,IP包提交給下層協議時將會得到怎樣的處理呢?這就取決於數據鏈路層協議了,一般的數據鏈路層協議都會負責將IP包分割成更小的幀,然後在目的端重組它。在EtherNet上,數據鏈路幀的大小如以上幾位大俠所言。而如果是IP   over   ATM,則IP包將被切分成一個一個的ATM   Cell,大小爲53字節。
******************************************************************************************************************************
    TCP提供的是一種面向連接的,可靠的字節流服務,TCP提供可靠性的一種重要的方式就是MSS。通過MSS,應用數據被分割成TCP認爲最適合發送的數據塊,由TCP傳遞給IP的信息單位稱爲報文段或段(segment)。代表一個TCP socket的結構體struct tcp_sock中有多個成員用於確定應用數據被分割成最大爲多大的數據塊較爲合適(最大報文段長度MSS)。
    我們不難聯想到,跟最大報文段長度最爲相關的一個參數是網絡設備接口的MTU,以太網的MTU是1500,基本IP首部長度爲20,TCP首部是20,所以MSS的值可達1460(MSS不包括協議首部,只包含應用數據)。
    前面的TCP三次握手協議中我們看到,通訊的雙方都通過TCP選項通告了自己期望接收的MSS值,該值直接來源於struct tcp_sock的成員advmss,而這個值直接取自於網絡設備接口的MTU減去IP首部和TCP首部的長度。在本地以太網中可達1460(如果首部都不含選項的話)。而成員rx_opt是一個結構體struct tcp_options_received,它記錄的是來自對端的TCP選項通告,其成員mss_clamp表示mss的上限值,其來源就是對端的MSS通告,而mss_user是用戶設置的mss,其優先級最高,如果有user_mss,則使用user_mss,忽略其它。
    從上面我們可以看到,MSS是可以通過SYN段進行協商的(MSS選項只能出現在SYN報文段中),但它並不是任何條件下都可以協商的,如果一方不接受來自另一方的MSS值,並且沒有user_mss,則MSS就定爲默認值536字節(加上首部,允許576字節的IP數據報)。實際上,struct tcp_sock->rx_opt->mss_clamp的初始值就定爲536,等收到來自對端的MSS通告後,才進行修改。而結構體struct tcp_sock的成員mss_cache用於緩存上次的有效的mss,其初始值也被定爲536。
    函數mytcp_sync_mss爲一個tcp socket中的mss相關的成員進行數據同步,其基本的一個算法是:
    1、當前的MSS正常情況下應該爲mtu-IP首部-TCP首部(不包括選項)。
    2、struct tcp_sock->rx_opt->mss_clamp中含有對端通告的能夠接受的MSS值,如果該值小於第一步計算所得到的MSS,則以該值爲準。
    3、IP首部如果帶有IP選項,則MSS中要減去選項長度。
    4、如果MSS已經小於48了,則令其等於48。
    5、減去TCP首部中選項的長度。
    6、如果MSS當前已經大於滑動窗口大小的1/2,則取滑動窗口大小的1/2作爲MSS值(但不能小於48)。
    7、成員mss_cache用於緩存下剛剛計算所得的MSS。
    所以,說本地以太網中MSS爲1460的說法並不正確,它還會動態變化,如果IP首部和TCP首部中出現選項,則MSS要相應的減小,一般TCP首部中會有12字節的時間戳選項(外加兩字節的填充選項),這時的MSS就等於1448。
    MSS的主要作用是限制另一端主機發送的數據的長度,同時,主機本身也控制自己發送數據報的長度,這將使以較小MTU連接到一個網絡上的主機避免分段。
    struct tcp_sock有一個成員xmit_size_goal,用於記錄該socket發送數據報時的segment的大小,一般情況下它的值就等於MSS(特殊情況有例外,以後再分析)。
----------------------------------------
 
以太網(IEEE 802.3)幀格式:
1、前導碼:7字節0x55,一串10間隔,用於信號同步
2、幀起始定界符:1字節0xD5(10101011),表示一幀開始
3DA(目的MAC)6字節
4SA(MAC)6字節
5、類型/長度:2字節,01500保留爲長度域值,153665535保留爲類型域值(0x06000xFFFF)
6、數據:461500字節
7、幀校驗序列(FCS):4字節,使用CRC計算從目的MAC到數據域這部分內容而得到的校驗和。
CSMA/CD作爲MAC算法的一類LAN稱爲以太網。CSMA/CD衝突避免的方法:先聽後發、邊聽邊發、隨機延遲後重發。一旦發生衝突,必須讓每臺主機都能檢測到。關於最小發送間隙和最小幀長的規定也是爲了避免衝突。
考慮如下的情況,主機發送的幀很小,而兩臺衝突主機相距很遠。在主機A發送的幀傳輸到B的前一刻,B開始發送幀。這樣,當A的幀到達B時,B檢測到衝突,於是發送衝突信號。假如在B的衝突信號傳輸到A之前,A的幀已經發送完畢,那麼A將檢測不到衝突而誤認爲已發送成功。由於信號傳播是有時延的,因此檢測衝突也需要一定的時間。這也是爲什麼必須有個最小幀長的限制。
按照標準,10Mbps以太網採用中繼器時,連接的最大長度是2500米,最多經過4箇中繼器,因此規定對10Mbps以太網一幀的最小發送時間爲51.2微秒。這段時間所能傳輸的數據爲512位,因此也稱該時間爲512位時。這個時間定義爲以太網時隙,或衝突時槽。512位=64字節,這就是以太網幀最小64字節的原因。
512位時是主機捕獲信道的時間。如果某主機發送一個幀的64字節仍無衝突,以後也就不會再發生衝突了,稱此主機捕獲了信道。
由於信道是所有主機共享的,如果數據幀太長就會出現有的主機長時間不能發送數據,而且有的發送數據可能超出接收端的緩衝區大小,造成緩衝溢出。爲避免單一主機佔用信道時間過長,規定了以太網幀的最大幀長爲1500
100Mbps以太網的時隙仍爲512位時,以太網規定一幀的最小發送時間必須爲5.12μs
1000Mbps以太網的時隙增至512字節,即4096位時,4.096μs
*************************************
MTU的含義: MAC幀內的數據(Payload)字段的最大長度
    我們使用Ping命令時, -l參數所指定的數據包大小, 是指的ICMP報文中的ICMPData字段的長度,不包括ICMP Header,更不包括IPHeader.
以太網封裝IP數據包的最大長度是1500字節,也就是說以太網最大幀長應該是以太網首部加上1500,再加上7字節的前導同步碼和1字節的幀開始定界符,具體就是:7字節前導同步嗎+1字節幀開始定界符+6字節的目的MAC+6字節的源MAC+2字節的幀類型+1500+4字節的FCS。
按照上述,最大幀應該是1526字節,但是實際上我們抓包得到的最大幀是1514字節,爲什麼不是1526字節呢?原因是當數據幀到達網卡時,在物理層上網卡要先去掉前導同步碼和幀開始定界符,然後對幀進行CRC檢驗,如果幀校驗和錯,就丟棄此幀。如果校驗和正確,就判斷幀的目的硬件地址是否符合自己的接收條件(目的地址是自己的物理硬件地址、廣播地址、可接收的多播硬件地址等),如果符合,就將幀交“設備驅動程序”做進一步處理。這時我們的抓包軟件才能抓到數據,因此,抓包軟件抓到的是去掉前導同步碼、幀開始分界符、FCS之外的數據,其最大值是6+6+2+1500=1514。
以太網規定,以太網幀數據域部分最小爲46字節,也就是以太網幀最小是6+6+2+46+4=64。除去4個字節的FCS,因此,抓包時就是60字節。當數據字段的長度小於46字節時,MAC子層就會在數據字段的後面填充以滿足數據幀長不小於64字節。由於填充數據是由MAC子層負責,也就是設備驅動程序。不同的抓包程序和設備驅動程序所處的優先層次可能不同,抓包程序的優先級可能比設備驅動程序更高,也就是說,我們的抓包程序可能在設備驅動程序還沒有填充不到64字節的幀的時候,抓包程序已經捕獲了數據。因此不同的抓包工具抓到的數據幀的大小可能不同。下列是本人分別用wireshark和sniffer抓包的結果,對於TCP 的ACK確認幀的大小一個是54字節,一個是60字節,wireshark抓取時沒有填充數據段,sniffer抓取時有填充數據段。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章