Inside TCP/IP 讀書記錄

把一些筆記轉到blog上來,以免丟失。


中文RFC:www.cnpaf.net




-----------------------Chapter 1 概述----------------------------------


當前的以太網已經從總線型改爲了(以集線器和交換機爲核心的)星型網絡。




TCP傳給IP的數據單元稱作TCP報文段或簡稱爲TCP段(TCP segment、報文段)。IP傳給網絡接口層的數據單元稱作IP數據報(IP datagram)。通過以太網傳輸的比特流稱作幀(Frame)(數據幀)。
以太網數據幀的物理特性是其長度必須在46~1500字節之間。(數據部分)


大多數TCP/IP實現給臨時端口分配1024~5000之間的端口號。大於5000的端口號是爲其他服務器預留的(Internet上並不常用的服務)






---------------------Chapter 2 數據鏈路層-------------------------------
以太網的IP數據報封裝格式是在RFC894中定義。IEEE802的IP數據報封裝格式是在RFC1042中定義。
兩種格式長度相同,但內部數據區結構不同。


以太網數據幀的最小長度爲60字節,若包括以太網幀尾還要再加4字節爲64字節。
以太網封裝(rfc894)= 6byte目的地址 + 6byte源地址 + 2byte類型 + 46-1500byte數據 + 4byte以太網幀尾CRC。


Internet主機必須能夠發送和接收RFC894(以太網)封裝格式的分組。
硬件地址一般爲48bit(6字節)。
ARP和RARP完成對32bit的IP地址和48bit的硬件地址進行映射。


PPP協議用於改進SLIP協議,最終會代替SLIP。
PPP用在串行鏈路上的通信,支持多協議(封包格式),帶校驗(CRC)。 PPP協議幀。


MTU:網絡鏈路層特徵。
以太網(1500字節)和IEEE 802(1492字節)對數據幀的最大長度有限制。這個特性稱爲MTU。
有時(以太網、s令牌環、802等)(可能)是物理特性,有時(PPP、SLIP)是邏輯限制(爲得到足夠快的響應時間)。
路徑MTU:兩臺主機通信時,路徑上的最小MTU。


以太網MSS爲1460字節。802.3的MSS爲1452字節。








-----------------------------------------Chapter 3 IP-----------------------------------------
IP層提供不可靠、無連接的服務。
1、不可靠:不保證IP數據報能成功到達目的地。如果網絡層上的某個路由器緩衝區用完,IP會丟棄數據報,發ICMP消息給信源端。由上層(傳輸層或應用層)自己負責可靠性。
2、無連接:不維護任何關於後續數據報的狀態信息。(無狀態)。每個數據報的處理是相互獨立的。(數據報的到達不是有序的)。




每個IP數據報都進行獨立的路由選擇??????




IP首部(基本字段共20byte) = 
4bit版本號 + 4bit首部長度(32bit的數目) + 8bit服務類型 + 16bit總長度
+ 16bit標識 + 3bit標誌位 + 13bit片偏移
+ 8bit生存時間(TTL) + 8bit協議 + 16bit首部校驗和
+ 32bit源IP地址
+ 32bit目的IP地址
+ 可選項(也算首部的內容)
+ 數據


首部長度:標示有幾個32bit。所以首部最大可以有32bit*15=60字節。
TOS:包含最小時延、最大吞吐量、最高可靠性、最小費用。
總長度:整個IP數據報的字節數。結合首部長度,可以確定數據開始位置和長度。16bit決定了ip數據報最長爲65535字節。
標識字段:發送序號???
TTL:設置數據報可以經過的最多路由器數。源主機設置,通常爲32或64。每經過一個路由器減1。當值爲0時,數據報丟棄,發送ICMP報文通知給源主機。


首部校驗和:
只是對首部的校驗和,不覆蓋數據部分。 但ICMP、IGMP、tcp、udp首部中的校驗和覆蓋首部和數據部分。
校驗和驗證失敗時,丟棄數據報,但不發送差錯報文,由上層發現報文丟失並重傳。


校驗和算法:對每個16bit進行二進制反碼求和。(發送方計算時,對校驗和本身所在bit位,先置位0,再計算;接收方計 算時,直接對所有16bit位計算,則結果應該全爲1。)
ICMP、IGMP、UDP和TCP都採用相同的檢驗和算法。


IP中的可選字段:(作用)
記錄路徑(路由器IP)、時間戳(路由ip和時間)、源站選路(寬鬆、嚴格)、安全和處理限制(軍用)
可選字段以32bit作爲界限(IP首部長度以32bit整數倍計算)。




保留IP:
A類:10.0.0.0--10.255.255.255
     127.0.0.0--127.255.255.255
B類:172.16.0.0--172.31.255.255
C類:192.168.0.0--192.168.255.255


地址分類:
A類:0.0.0.0-127.255.255.255       0
B類:128.0.0.0-191.255.255.255 10
C類:192.0.0.0-223.255.255.255 110
D類:224.0.0.0-239.255.255.255 1110
E類:240.0.0.0-247.255.255.255 11110








----------IP路由選擇---------


IP層既可以配置成路由器功能,也可以配置成主機功能。
大多數用戶系統都可以配置成一個路由器。
IP層在內存中有一個路由表。


路由表項:
1、目的IP地址(主機地址或網絡地址)
2、下一站路由器IP或直接連接的網絡IP地址
3、標誌位(其一指明目的IP地址是網絡地址還是主機地址;其二,指明下一站路由器IP是路由器還是直接連接的網絡接口)
4、網絡接口


路由選擇功能:(搜索路由表)
1、尋找與目的IP地址完全匹配的表目(網絡號和主機號都匹配)。
2、尋找與目的網絡號相匹配的表目。
3、尋找標爲“默認”的表目。


如果以上路由過程都失敗,則向生成數據報的引用程序返回一個“主機不可達”或“網絡不可達”的ICMP差錯報文。




爲一個網絡指定一個路由器,而不必爲每個主機指定一個路由器。
Internet上的路由器的路由表中一般只有幾千個表目。




子網編碼:(因爲給A類和B類網絡地址的主機號分配了太大的空間。)
IP地址分爲網絡號和主機號,主機號又分爲子網號和主機號。
使用子網號可以減少路由表目。(因爲NIC上登記的IP地址纔在Internet路由表中存在。nic中只能申請網絡號。)




主機在引導時,需要配置IP地址。還需要知道哪些位是子網號和主機號。


子網掩碼:
網絡號和子網號bit爲1,主機號bit爲0。通常使用十六進制表示。比特掩碼。


給定IP地址,通過IP地址類型、子網掩碼,可以確定一個主機所在網絡的結構。(網絡號+子網號+主機號)。










網絡字節序: (big endian)
以32bit數據爲例,最高位在左邊記爲0bit,最低位在右邊記爲31bit。網絡傳輸時,先傳送高字節(0-7bit)。






-----------------------------------------Chapter 4 ARP-----------------------------------------


地址解析:實現IP地址和數據鏈路層地址的映射。
鏈路層地址只在同一廣播域中有效。以太網中,只在同一IP網段有效。
ARP把IP地址映射爲硬件地址(48bit)。


ARP是以太網環境下的地址轉換機制。


以太網和局域網的關係????? 以太網只是一種局域網組網方式。還有令牌環網等。
ARP只是局域網內主機通信所需要的協議????
局域網內主機間的通信,不需要IP地址。????


ARP請求在其所在的局域網中廣播,詢問哪個主機有這個IP地址。但應答不是廣播的,是直接回復給詢問者的。
ARP應答包含IP地址和其硬件地址。


點對點鏈路不使用ARP。在設置鏈路時,把每一端的IP地址告知給內核。




ARP數據幀(42字節) = 以太網首部(14byte) + ARP請求(應答)(28byte);
以太網首部 = 以太網目的地址(6byte)+ 以太網源地址(6byte) + 幀類型(2byte)
ARP請求(應答) = 硬件類型(2byte)+ 協議類型(2byte)+ 硬件地址長度(1byte)+ 協議地址長度(1byte)+ 
op(2byte)+ 發送端以太網地址(6byte)+  發送端IP地址(4byte)+ 目的以太網地址(6byte)+ 目的IP地址(4byte)




只有ARP的應答收到後,(即得到目標的物理地址後),TCP的SYN報文才會發送。


一個數據報要發給遠程主機(非局域網內部),是否也要ARP??? 中間鏈路上(源和目標的路由器之間)用ARP嗎???


ARP高速緩存的有效時間爲20min。不完整的表項(目標主機不存在)有效時間爲3min。
系統收到arp請求(或發送arp應答)時,會把請求端的IP和硬件地址放入緩存。
當收到免費ARP請求時,會自動更新到緩存。




ARP代理(委託ARP):ARP請求從一個網絡發往另一個網絡,連接這兩個網絡的主機就可以回答該ARP請求,就是ARP代理。
代理ARP的使用一般是使用在沒有配置默認網關和路由策略的網絡上的。 
如果主機配置了默認網關,若ARP請求查詢的對象在局域網外,則該查詢任務交給網關處理。
代理ARP只是解決跨局域網地址查詢的一種方法。使用默認網關是主流方法。


主機只會向其子網內的主機發ARP請求(局域網廣播)。
ARP請求以廣播的方式發出,被路由器限制在局域網之內。(路由器默認不轉發廣播)。
主機沒有配置路由信息的情況下,纔會把對外網IP的查詢在子網內廣播。
當對外網IP的查詢進行廣播時,如果路由器支持代理ARP,並且目標IP在路由器的路由表中,則路由器以目標IP和自己的MAC地址回覆該查詢。
如果要查詢的IP地址在主機(網絡接口)的子網內,則向子網內發ARP請求的廣播。如果要查詢的IP地址不在其子網內的,則去查路由表,而不會再發ARP廣播。
如果主機沒有配置路由信息(默認路由、默認網關),則無法分清哪些IP是外網的,所有MAC地址查詢都會進行ARP請求。




免費ARP: 查詢自己IP的ARP請求。一般發生在系統引導過程中。




主動端每發送一個IP數據報都要發一個ARP請求並等待應答嗎??? 不是。在局域網內部發送數據時才需要arp。


路由器之間會傳遞ARP請求嗎 ?????




------------------------------------------Chapter 5 RARP--------------------------------------


RARP使用於無盤系統引導階段。


RARP協議和ARP協議的格式相同。幀類型、op等字段不同。


RARP請求以廣播方式發送,RARP應答以單播方式發送。


RARP服務器的功能由用戶進程提供,不是內核的TCP\IP實現的一部分。
RARP服務器的實現與系統相關。






------------------------------------------Chapter 6 ICMP---------------------------------------


ICMP通常被認爲是IP層的一部分。


ICMP數據報 = IP頭部 + ICMP報文
ICMP報文 = ICMP報文頭 + 內容
ICMP報文頭(必含的8個字節) = 8bit類型 + 8bit代碼 + 16bit校驗和(必選) + 32bit類型相關數據(未用時必須爲0)(但對設置不可分片的IP數據報產生的不可達差錯報文中可以把路由器的出口MTU寫在低16位中。)
但ICMP報文頭裏只有前4個字節是相同的。


ICMP的校驗和是必須的。
icmp報文分:查詢報文和差錯報文。
差錯報文包括:產生差錯的IP數據報的首部(包含任何選項,不一定20字節)、產生差錯的IP數據報內容字段的前8個字節(對tcp是源端口+目標端+發送序列號;對udp是源端口+目標端口+udp長度+校驗和)。


路徑MTU發現:設置不可分片標記時,在需要分片的路由器位置產生不可達差錯報文,會把路由器的出口MTU寫在ICMP第二個四節的低16上。(ICMP不可達差錯報文通常使用8個字節的ICMP報文頭。)


對IP數據報,路由器緩存用完,則IP層丟棄該數據報,然後發送ICMP數據報給信源端。








不產生ICMP差錯報文的情況:
1、icmp差錯報文本身。
2、目標地址爲廣播、組播地址ip數據報。
3、用在鏈路層廣播的數據報。
4、不是第一個分片的ip數據報。
5、源地址不是單個主機地址的數據報。(如零地址、環回地址、廣播地址、多播地址)。




以太網首部爲14字節。
廣播的接收者包括髮送者本身。
ICMP報文是在主機之間交換的,不用端口號。




握手的過程會有icmp差錯報文嗎???
不可達差錯對tcp和udp都有效嗎???


用戶進程如何接收到ICMP差錯報文???
生成端口不可達差錯是否爲必須???


UDP協議時,對socket端口進行connect,可以接收ICMP差錯報文。???


ICMP報文需要內核處理的,那麼內核直接處理。(也可能發送ICMP報文的拷貝給用戶進程。)
ICMP報文需要用戶進程處理的,會傳送給所有內核中登記的用戶進程。












-----------------------------------------Chapter 9 IP選路--------------------------------------












------------------------------------------Chapter 11 UDP---------------------------------------


UDP首部只有8個字節。(tcp有20字節)
UDP頭 = 16bit源端口 + 16bit目標端口
+ 16bitUDP長度(頭和數據) + 16bitUDP校驗和


tcp端口號和udp端口號是相互獨立的。???只是說tcp數據包只會傳給tcp,udp數據包只會傳給udp。在ip層就區分開了。
根據業務的需要,兩種協議也會選擇同一個端口號。


udp的校驗和是可選項;tcp的校驗和是必選項。
tcp和upd的校驗和都覆蓋其頭部和數據。IP首部的校驗和只覆蓋IP首部。
如果接收端發現校驗和(IP層、UDP層)有錯,就直接丟棄數據報而不產生差錯報文。
如果發送的校驗和爲0,則說明發送端沒有計算校驗和。如果有,接收端必須進行校驗。




UDP數據報在鏈路上傳輸時,有被路由器等設備修改的可能。所以需要校驗和。




UDP數據報和TCP段都包含一個12字節的僞首部。是爲計算校驗和而設置。 算長度時算在哪裏了???只是爲了計算校驗和,不傳送。


校驗和:16bit字(反碼)相加。所以,無法區分出數據報中16bit字交互位置。


數據鏈路層的CRC檢驗和tcp或udp校驗和,都是簡單的校驗和,不能檢測出所有可能的差錯。




udp數據報有分片的需求。tcp段通常沒有分片需求(mss小於等於mtu)。
在路徑的任何路由器上都可能出現對IP數據報的分片。
IP數據報被分片後,只有到達最終目的地才進行組裝。
分片和組裝發生在IP層,對上層(tcp、udp)透明。


發送一個大於MTU的數據報,但設置“不分片”標誌,會收到ICMP差錯報文。(應用層如何知道???)


一個UDP數據報被分片後,如有一個分片(IP數據報)丟失,就需要重傳整個UDP數據報。
IP層本身沒有超時重傳機制。而且起始端也不知道中間路由器如何分段的。(TCP有超時和重傳,UDP沒有。)


UDP數據報被分片後,UDP頭部只出現在第一個分片中。


IP數據報指IP層端到端的傳輸單元(分片前和重新組裝後)。(因爲分組和重裝都是在IP層完成,對上層透明。)
分組是在IP層和數據鏈路層之間傳遞的數據單元。
一個分組可是一個完整的IP數據報,也可以是IP數據報的一個分片。
分組也是以一個IP數據報的形式傳送的。??? 第一個分片是結構完整(ip頭+udp頭+數據)的IP數據報,其餘的是缺少UDP頭部的IP數據報。(如果是tcp,則缺少tcp頭部。)




ICMP不可達差錯(需要分片):
可用來進行路徑MTU發現。


採用UDP的路徑MTU發現:
IP定時器週期性(30s或更大間隔)把DF置1,以查看路徑MTU是否增大了。




ICMP組裝超時差錯:在目標端重新組裝數據時出錯或超時。


UDP的接收端在接到一個分片後,會啓動一個定時器(30s或60s),如果在定時器超時時,數據報的分片沒有全部到達,則丟掉這些數據報分片。但許多實現不產生ICMP組裝超時差錯。所以,一個數據報太大而造成分片太多時會增加無法送達的風險。


tcpdump: frag 74942:512@1024+) 
74942代表IP數據報序號;512表示當前的分片的長度;1024代表當前分片對原始IP數據報首位置的偏移量;+表示還有更多分片。


UDP數據報長度:應用程序數據一般限制爲512字節。
應用程序讀取數據報發生截斷時,有些實現(Berkeley)丟棄剩餘部分,有些實現(SVR4)不丟棄可繼續讀。


ICMP原站抑制差錯:
當接收端(包括路由器)的接收緩衝滿時,可能(不是必須)會發送ICMP原站抑制(source quench)差錯。
新的RFC認爲路由器不應該產生原站抑制差錯報文。




IP_RECVDSTADDR


每個UDP端口都有一個輸入隊列。


1、應用程序不知道輸入隊列溢出。
2、udp丟棄數據報時,不告知客戶端。(無icmp差錯報文)。
3、UDP輸出隊列是FIFO的。






一臺機器上的多個服務器(進程)可以使用不同的IP和相同的端口號,但後面(第二個開始)啓動的服務器必須指定SO_REUSEADDR告知系統。
一臺機器上的多個服務器(進程)要使用相同的IP和相同的端口號,則需要同時指定SO_REUSEADDR和SO_REUSEPORT(從第一個啓動的服務器開始)。(只用於UDP多播???)(有人測試沒有使用SO_REUSEPORT也沒影響。???)


一個進程綁定不同的ip,相同的端口,到多個socket上,需指定SO_REUSEADDR。




SO_REUSEADDR可以用在以下四種情況下。
(摘自《Unix網絡編程》卷一,即UNPv1)
1、當有一個有相同本地地址和端口的socket1處於TIME_WAIT狀態時,而你啓動的程序的socket2要佔用該地址和端口,你的程序就要用到該選項。
2、SO_REUSEADDR允許同一port上啓動同一服務器的多個實例(多個進程)。但每個實例綁定的IP地址是不能相同的。在有多塊網卡或用IP Alias技術的機器可以測試這種情況。
3、SO_REUSEADDR允許單個進程綁定相同的端口到多個socket上,但每個socket綁定的ip地址不同。這和2很相似,區別請看UNPv1。
4、SO_REUSEADDR允許完全相同的地址和端口的重複綁定。但這隻用於UDP的多播,不用於TCP。








------------------------Chapter 15 TFTP:簡單文件傳輸協議----------------------


TFTP是一個簡單的協議,適合於只讀存儲器,僅用於無盤系統進行系統引導。它只使用幾種報文格式,是一種停止等待協議。


最初用於引導無盤系統。
基於UDP。要處理分組丟失和分組重複。 


支持netascii和octet模式文件。默認使用netascii。




5種TFTP報文格式:
1、操作碼(1=RRQ/2=WRQ)(2byte)+ 文件名(nbyte)+ 0(1byte)+ 模式(nbyte)+ 0(1byte)
2、操作碼(3=date)(2byte)+ 塊編號(2byte)+ 數據(0-512byte)
3、操作碼(4=ACK)(2byte)+ 塊編號(2byte)
4、操作碼(5=error)(2byte)+ 差錯碼(2byte)+ 差錯信息(nbyte)+ 0(1byte)


停止等待協議。
特別之處: 服務器收讀寫請求報文是在TFTP的熟知端口(69),而回複數據是使用新的端口。






------------------------Chapter 17 TCP:傳輸控制協議---------------------------


tcp提供可靠性的方式:
1、應用數據被tcp分隔成合適大小的塊,傳輸過程中數據報長度保持不變(與udp不同)。
2、超時重發。
3、收到數據後,發確認。(但不立即發確認,推遲200ms後確認)。
4、帶校驗和。(強制的。udp的校驗和是可選的。)
5、TCP會對收到的數據重新排序,以便把有序的數據交給應用層。 IP數據報可能無序到達,所以TCP報文段也可能無序到達。
6、TCP會丟棄重複報文段。(IP數據報會重複)。
7、TCP提供流量控制機制。






TCP首部 = 源Port(16bit)+ 目標Port(16bit)
+ 發送序號(32bit)
+ 確認序號(32bit)
+ 首部長度(4bit)+保留位(6bit)+ 標誌位(URG + ACK + PSH + RST + SYN + FIN)(各1bit) + 窗口大小(16bit)
+ 校驗和(16bit)+ 緊急指針(16bit)
+ 選項(一般不存在)


TCP報文段 = TCP首部(20字節) + TCP數據
IP數據報 = IP首部(20字節) + TCP報文段






TCP段中的發送序號:tcp連接對持續發送字節流的每個字節進行計數,其值標記tcp報文段第一個數據字節在整個字節流中的序號。 
TCP報文段的序號還是字節流中字節的序號??? 字節序號
syn的初始序號(ISN)怎麼算???  (系統初始化爲1,每4ms加1,每個連接的可獲取到的ISN不同。每次建立一個連接ISN加64000。) 


TCP段中的確認序號:是接收端給發送端的,指明接收端期望下一個收到的報文段的序號。(發送序號 + 1)


TCP傳輸是全雙工的。兩個方向上的發送序號獨立。


TCP的確認序號,不能選擇確認,只能按序確認。而且不能對錯誤的報文段進行否認。


MSS(Maximum Segment Size)在可選字段中。連接方在通信的第一個報文段(爲建立連接而設置SYN標誌的那個段)中指明MSS。






--------------------------------------Chapter 18 TCP連接的建立和終止----------------------------------------


nastygram 聖誕樹分組


主動連接(打開)端發SYN,被動連接(打開)端發SYN+ACK。主動端再發一個ACK。完成連接。


主動斷開方發FIN+ACK,被動斷開方發ACK,完成一個方向的連接斷開。另一個方向的斷開過程相同。
爲何斷開連接時,被動斷開端要先ACK,而沒有使用FIN+ACK一個報文段完成確認和斷開??? tcp連接是全雙工的,所以每個方向必須單獨地進行關閉。可能此時被動斷開端還有需要向主動斷開端發送數據,所以不能在收到fin後同時關閉寫連接。




握手(連接建立)過程只需不到0.01s。
握手時,syn包超時,再次發syn包的間隔會越來越大。(如第一次爲5.8s,第二次爲24s,然後48s後超時。非精準數據)
大多數伯克利系統將建立一個新連接的最長時間限制爲75s。(TCP連接超時的定時器爲500ms。)




socket api close() 是同步過程嗎??? 
close()只能斷開一個方向的連接嗎??? 斷開兩個方向上的連接。 
shutdown()可以指明只斷開一個方向上的連接。另一個方向上的連接還可以繼續發送數據。
close()是指明瞭不接收對端再寫數據了,以及對端寫緩衝區裏的數據都要被丟棄嗎??? ???


FIN的ACK包、SYN的ACK包都是系統自己產生,不需要程序員處理。
SYN_RCVD狀態時,收到RST,會再回到LISTEN狀態。




MSS(Maximum Segment Size)表示TCP傳往另一端的最大塊數據的長度。不包括tcp頭和ip頭。
MSS只能出現在SYN報文段中。如果一方不接受來自另一方的MSS值,則MSS就定爲默認值536字節。(MTU值 - IP頭長度 - TCP頭長度)
以太網MSS爲1460字節。802.3的MSS爲1452字節。BSD系統要求MSS爲512的倍數。
握手時,兩個主機只知道自己出口的MTU,並不知道路徑上的MTU。所以如果路徑上MTU小於兩個主機自己報的MTU(MSS+40),仍然會出現重新分段。 ???是的。
mss只能在SYN包中指定。
mss不包含ip頭和tcp頭大小。mss = 外出接口上的MTU - IP頭 -TCP頭。
如果目的IP地址爲非本地,則mss通常選默認值536。
每個peer知道自己外出接口上的MTU,但不知道路徑上的MTU,若路徑上的mtu小,仍可能出現分包現象。




MSL:tcp報文段的最大生存時間。通常爲2分鐘。
TTL:IP數據報的最大生存時間。使用跳數,不是定時器。


TIME_WAIT:用於防止fin的最後一個ACK(主動關閉方發出的ack)丟失重傳時出現混淆。只有主動關閉的一方纔會進入這個狀態。
同時,會導致這個連接(五元組)在2msl內不可用。伯克利tcp,強制在2msl內,本地端口不能再被使用。








RST:


UDP協議發包時,對端port不可用,會產生ICMP報文。 TCP協議連接時,對端port不可用,會產生RST包。


Socket API 通過“linger on close”選項(SO_LINGER)提供連接異常關閉的能力,即發送RST包,(丟棄緩衝區裏的待發送數據)。


接收到RST報文段的一端,直接斷開連接,通知應用層復位,不進行確認(ACK)。


如果so_linger設置了超時時間,對非阻塞的fd,closesocket是否會阻塞????






TCP連接使用keepalive選項,可以幫助發現半打開(half-open)(比如一端突然斷電、拔掉網線重啓程序)的連接。


對於半打開連接發出的數據報,TCP的處理原則是接收方以復位(RST包)應答。




同時打開:
每一方必鬚髮送syn,且這些syn必須傳遞給對方。(這需要每一方使用對方知道的地址和端口)。


同時關閉:
兩端各發一個fin,都進入fin_wait_1狀態。收到對端的fin後,發ack,並進入closing狀態。各自收到ack後,進入time_wait狀態。




只有處於LISTEN狀態的進程能接收SYN報文段。而只有處於ESTABLISHED狀態的進程能接收數據報文段。




backlog:積壓值。即連接隊列的長度(BSD上與長度不一致),取值0-5,通常使用5。
已被TCP接受(已完成三次握手),而等待被應用層接受的最大連接數。 與最多連接數、併發處理的客戶數無關。
被tcp接受的連接,加入連接隊列;應用層接受該連接後,從連接隊列中取出。




主動打開是通過connect完成的嗎? connect返回,表示三次握手完成嗎? 這時候被動打開方的應用層是否已經接受了連接(即應用層是否知道新連接)。
三次握手完成,connect就返回。此時,可能應用層還未接受連接(accept),但connect發起端已經可以發送數據了。
對客戶端而言,三次握手完成,就表示主動打開成功。






當服務器握手完成,服務器的應用層沒有接收(還不知道)這個新連接時,服務器的tcp僅將收到的數據放入緩衝區。


如果服務器的連接隊列滿,服務器將不再處理syn包,也不發回rst包。客戶端的主動打開會超時。
如果服務器程序未啓動,客戶端會收到rst。


TCP服務器無法使客戶進程的主動打開失效。因爲三次握手完成後,客戶端的主動打開就算成功了。而服務器端是在應用層拿到這個新連接後才能知道客戶端的ip和port,這時候連接已經被服務器的應用層接受了,要想拒絕就只能關閉了(發fin or rst)。




-------------------------------------------Chapter 19 TCP的交互數據流------------------------------------------------


捎帶ack的發送方式:
等待200ms(內核計時,和接收時間無關)再發送ack,儘量把ack和下一個包合併(如放在push的數據包中)。
經受時延的ack。
Nagle算法:
tcp連接上最多隻有一個未被確認的分組,在收到ack包之前,累積數據,收到ack包之後,發送緩衝區使用一個tcp報文段,把累積的數據發送過去。是累積發送的一種方式。
TCP_NODELAY可以關閉Nagle算法。(設置PUSH標誌也是這樣的作用。)




-------------------------------------------Chapter 20 TCP的成塊數據流------------------------------------------------


窗口更新:
當接收端緩衝區滿後,通告給發送端停止發送;但等接收端緩衝區內的數據被讀出(全部?不需全部,只要被應用層部分讀出)後,接收端會再給發送端發ack包通告滑動窗口張開。
許多TCP實現在窗口大小增加了兩個最大報文段長度(2MSS)或者最大可能窗口的50%時發送這個窗口更新。


對以太網而言,默認的4096字節並不是最理想的大小,將兩個緩存增加到16384個字節可以增加約40%左右的吞吐量。


4.4BSD默認發送和接收緩衝區大小爲8k或16k。




慢啓動算法需要在客戶端增加一個擁塞窗口(cwnd)。 一次連續發送擁塞窗口大小(初始化爲1mss)的數據包,每確認(ack)一個,窗口大小增加一個,從而實現指數增長。
擁塞窗口是發送方使用的流量控制;通告窗口是接收方使用的流量控制。


使用帶寬時延乘積衡量網絡管道的容量。


緊急方式發送的數據不是帶外數據。(ie:被通告窗口爲0時,可以使用緊急方式發送數據給接收端。)


使用緊急報文來指明緊急數據的開始(緊急狀態開始)。緊急指針指向緊急數據結束位置(緊急數據的最後一位)。數據裏(部分)帶有緊急數據,則需要指明URG字段爲1;一旦不在該包數據區間裏,則URG置0,緊急狀態結束。 
緊急數據必須放置在報文數據的開始位置???




tcp爲應用層提供的是有序數據,如果出現丟包,應用層無法讀到失序的數據?????丟包則後續數據未被確認。








-------------------------------------------Chapter 21 TCP的超時與重傳-------------------------------------------------




指數退避(exponential backoff)


如果正常連接被斷開網線,數據會多次重傳,並最終在大約9分鐘時放棄(RST鏈路)。對大多數實現,這個時間是不可調整的。


RTO(Retransmission TimeOut): 重傳超時時間。在RTT的基礎上進行平滑算法所得。RTT估計器。上限爲64s。
RTT(Round Trip Time)


重傳多義性問題: 
Karn算法:在一個超時和重傳發生時,在重傳數據的確認達到之前,不能更新RTT估計器。


快速重傳:
伯克利TCP對收到的重複ACK進行計數,當收到3個重複的ack,則認爲該報文段丟失並重傳這個報文段。
快速重傳:
當一個序號的push包被確認(ack)後,又連續收到3個確認(ack)該序號的包,則認爲以該序號開始的包丟失,立即重傳這一個包。這就是Jacobson的快速重傳算法。
在重傳後,不需要等待接收方確認重傳,發送方繼續正常的發送數據。


慢啓動算法是在一個連接上發起數據流的方法;擁塞避免算法是一種處理丟失分組的方法。是兩個目的不同的獨立算法。在實際中,兩個算法通常一起實現。
兩個算法需要對每一個連接維持兩個變量:一個擁塞窗口(cwnd)和一個慢啓動門限(ssthresh)。
算法工作過程:
1、對於一個給定連接,初始化cwnd爲1mss,ssthresh爲65535字節。
2、發送數據量不能超過min(cwnd, 通告窗口大小)(即爲當前發送窗口)。
3、當擁塞發生時(超時或收到重複ack),ssthresh設置爲當前發送窗口大小的一半(但最少爲2mss)。如果是超時引起擁塞,cwnd設置爲1mss(慢啓動)。
4、當收到新的ack時,增加cwnd大小。增加方法:if(cwnd <= ssthresh) 進行慢啓動;else 進行擁塞避免。


擁塞避免:
是發送方使用的流量控制;通告窗口是接收方使用的流量控制。
在cwnd達到ssthresh之前,每收到一個確認(ack),cwnd增加1,同時多發送一個push。這就是慢啓動階段。
當cwnd達到ssthresh大小時,每收到一個確認(ack),cwnd增加1/cwnd,(即一個rtt時間,cwnd增加1)。這就是擁塞避免階段。




(超時重傳和丟包重傳):


一、TCP認爲網絡擁塞的主要依據是它重傳了一個報文段。TCP對每一個報文段都有一個定時器,稱爲重傳定時器(RTO),當RTO超時且還沒有得到數據確認,那麼TCP就會對該報文段進行重傳,當發生超時時,那麼出現擁塞的可能性就很大,某個報文段可能在網絡中某處丟失,並且後續的報文段也沒有了消息,在這種情況下,TCP反應比較“強烈”:
1.把ssthresh降低爲cwnd值的一半
2.把cwnd重新設置爲1       (慢啓動)
3.重新進入慢啓動過程。
二、其實TCP還有一種情況會進行重傳:那就是收到3個相同的ACK。TCP在收到亂序到達包時就會立即發送ACK,TCP利用3個相同的ACK來判定數據包的丟失,此時進行快速重傳,快速重傳做的事情有:
1.把ssthresh設置爲cwnd的一半
2.把cwnd再設置爲ssthresh的值(具體實現有些爲ssthresh+3)  (快速恢復)
3.重新進入擁塞避免階段。




注意,冗餘ACK是不能捎帶的。




擁塞避免是發送方使用的流量控制,通告窗口是接收方進行的流量控制。
4.3bsd reno上慢啓動總是被執行。


擁塞避免時,慢啓動窗口加數增長。每經過一個RTT,cwnd加1。 一個RTT如何確定???從一個包發出,到收到該包的ack,這個時間段爲rtt。


慢啓動過程中,當cwnd達到ssthresh的大小時,慢啓動結束,同時進入擁塞避免。擁塞避免過程中,cwnd線性增長(一個rtt,加1)到發送超時,cwnd置1,ssthresh減爲當前發送窗口一半(最小爲2mss)。這時cwnd < ssthresh,再次進入慢啓動過程。重複前面的過程。


ssthresh(慢啓動閾值),表明估計擁塞窗口達到這個值時可能要出現擁塞了。所以此後就加法增大cwnd。




分組丟失的兩種標識: 
1、發生超時。
2、收到重複的確認。




如果由於報文段的重新排序而發送重複的ack,則重複ack個數只可能有1-2個。 ???


快速重傳:
當出現擁塞時(3個重複ack),不需等待發送超時,直接重傳丟失的報文段,這就是快速重傳。同時也進入擁塞避免。


快速恢復:
在出現擁塞之後,再收到重複ack,說明接收端收到了新的失序數據,併成功收下了。此時,cwnd線性增加(每收到一個重複ack,增加1)。這樣丟失的報文段之後發送的報文段就能繼續有效。一旦快速重傳發送的報文段被確認(收到ack),那麼從丟失報文到第一個重複ack之間的報文段都有效。這就是快速恢復。




ICMP差錯:
TCP能夠遇到的最常見的ICMP差錯就是源站抑制、主機不可達和網絡不可達。
當收到原站抑制時,引起cwnd置爲1,進入慢啓動。
當發生主機不可達或網絡不可達時,不必關閉連接。通常需要重新查找路由。




發生超時重傳時,tcp可能不是發送最初的分組,而包含了後續數據,重新分組,以儘可能大(1mss內)的分組把數據發出去。






--------------------------------------------Chapter 22 TCP的堅持定時器------------------------------------------------


接收ack的一方不對ack報文進行確認。 所以,用於窗口更新的ack報文丟失,會造成一直等待而連接終止。所以需要窗口探查。


窗口探查:發送方週期性地向接收方查詢窗口是否張開(變大)。


當收到通告窗口爲0時,啓動堅持定時器。窗口打開後,堅持定時器關閉。
堅持定時器使用TCP指數退避。超時時間指數增大,直至60s。




窗口探查時,如果窗口沒有打開,接收方會回ack包,但不確認用於探查的一字節數據;
一旦出現窗口打開,是否會確認用於探查的這一個字節。??? 不會了。
窗口探查包有特殊標記嗎???




糊塗窗口綜合症(Silly Window Syndrome):由於對方通告的窗口太小(小於1mss),或者發送方也不等待達到一個mss的窗口,而發出不滿長度的報文段。
避免措施:(雙方或任一方)
1、接收方不通告小窗口。至少一個mss。
2、發送方滿足下列條件之一才發送數據:a)可以發送一個滿長度的報文。b)可以發送至少是通告窗口一半大小的報文段。c)可以發送任何數據並且不希望接收ACK,或禁止了Nagle算法。


通告了一個大於1mss窗口(n),但發送方只用了1mss(m),而剩餘的不足1mss(n-m),此時,接收方仍通告(n-m)大小的窗口。因爲滑動窗口的右邊沿通常不能左移(窗口收縮)。






-----------------------------------------Chapter 23 TCP的保活定時器-----------------------------------------


一個tcp連接建立後,即使雙方沒有發送數據,連接也可以保持很久(幾個月)。


保活功能可以幫助服務器發現半打開的連接。(客戶端直接掉線、斷電等造成沒有發close)。


保活定時器週期爲2小時。一個連接在2小時內沒有動作,服務器就發送探查報文段。
1、如果客戶端已經崩潰或重啓中,則服務器無法收到響應,服務器會嘗試10次,每次間隔75s。10次無法收到響應,則認爲客戶端已經斷開。
2、如果客戶端已重啓完成,則服務器的探查會收到一個RST報文段的迴應,服務器終止這個連接。
3、如果路由鏈路出現問題(如線路斷開、路由器關閉),保活端會收到ICMP差錯報文(軟差錯),保活會嘗試10次,間隔75s。




探查報文如何發現客戶端已經重啓過了?????


------------------------------------------Chapter 24 TCP的未來和性能---------------------------------------
 
TCP在高速網絡環境中,有缺陷。


長肥管道(long fat pipe):具有很大帶寬時延乘積的網絡。長肥網絡。




路徑MTU發現:
IP首部設置DF,如果該IP數據報長度超過MTU,那麼路由器返回ICMP不可達差錯(不能分片差錯)。




TCP的路徑MTU發現:在連接建立時, TCP使用本端和對端MSS的最小值作爲起始的報文段大小。路徑MTU發現不允許TCP超過對端聲明的MSS。如果對端沒有指定一個MSS,則默認爲536。


大分組、小分組:
分組不一定是越大越好。














----------------------------------------------Chapter 27 FTP-------------------------------------------------




FTP最早的設計是用於兩臺不同的主機,這兩個主機可能運行在不同的操作系統下、使用不同的文件結構、並可能使用不同字符集。


採用兩個tcp連接傳輸一個文件: 
1、控制連接。(最大限度減小延遲)。
2、數據連接。(最大限度提高吞吐量)。




通常由Unix實現的FTP 客戶和服務器把我們的選擇限制如下:
• 類型:ASCI I或圖像。
• 格式控制:只允許非打印。
• 結構:只允許文件結構。
• 傳輸方式:只允許流方式。









































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