天天看點

TCP/IP協定棧與資料包封裝

TCP/IP協定棧與資料包封裝

  TCP/IP網絡協定棧分為應用層(Application)、傳輸層(Transport)、網絡層(Network)和鍊路層(Link)四層。如下圖所示(該圖出自[TCPIP])。 圖 36.1. TCP/IP協定棧

TCP/IP協定棧與資料包封裝

    兩台計算機通過TCP/IP協定通訊的過程如下所示(該圖出自[TCPIP])。 圖 36.2. TCP/IP通訊過程

TCP/IP協定棧與資料包封裝

      傳輸層及其以下的機制由核心提供,應用層由使用者程序提供(後面将介紹如何使用socket API編寫應用程式),應用程式對通訊資料的含義進行解釋,而傳輸層及其以下處理通訊的細節,将資料從一台計算機通過一定的路徑發送到另一台計算機。 應用層資料通過協定棧發到網絡上時,每層協定都要加上一個資料首部(header),稱為封裝(Encapsulation),如下圖所示(該圖出自[TCPIP])。 圖 36.3. TCP/IP資料包的封裝

TCP/IP協定棧與資料包封裝

      不同的協定層對資料包有不同的稱謂,在傳輸層叫做段(segment),在網絡層叫做資料報(datagram),在鍊路層叫做幀(frame)。資料封裝成幀後發到傳輸媒體上,到達目的主機後每層協定再剝掉相應的首部,最後将應用層資料交給應用程式處理。 上圖對應兩台計算機在同一網段中的情況,如果兩台計算機在不同的網段中,那麼資料從一台計算機到另一台計算機傳輸過程中要經過一個或多個 路由器,如下圖所示(該圖出自[TCPIP])。 圖 36.4. 跨路由器通訊過程

TCP/IP協定棧與資料包封裝

    其實在鍊路層之下還有實體層,指的是電信号的傳遞方式,比如現在以太網通用的網線(雙絞線)、早期以太網采用的的同軸電纜(現在主要用于有線電視)、光纖等都屬于實體層的概念。實體層的能力決定了最大傳輸速率、傳輸距離、抗幹擾性等。 集線器(Hub)是工作在實體層的網絡裝置,用于雙絞線的連接配接和信号中繼(将已衰減的信号再次放大使之傳得更遠)。 鍊路層有以太網、令牌環網等标準,鍊路層負責網卡裝置的驅動、幀同步(就是說從網線上檢測到什麼信号算作新幀的開始)、沖突檢測(如果檢測到沖突就自動重發)、資料差錯校驗等工作。 交換機是工作在鍊路層的網絡裝置,可以在不同的鍊路層網絡之間轉發資料幀(比如十兆以太網和百兆以太網之間、以太網和令牌環網之間),由于不同鍊路層的幀格式不同,交換機要将進來的資料包拆掉鍊路層首部重新封裝之後再轉發。 網絡層的IP協定是構成Internet的基礎。Internet上的主機通過IP位址來辨別,Internet上有大量路由器負責根據IP位址選擇合适的路徑轉發資料包,資料包從Internet上的源主機到目的主機往往要經過十多個路由器。 路由器是工作在第三層的網絡裝置,同時兼有交換機的功能,可以在不同的鍊路層接口之間轉發資料包,是以路由器需要将進來的資料包拆掉網絡層和鍊路層兩層首部并重新封裝。IP協定不保證傳輸的可靠性,資料包在傳輸過程中可能丢失,可靠性可以在上層協定或應用程式中提供支援。 網絡層負責點到點(point-to-point)的傳輸(這裡的"點"指主機或路由器),而傳輸層負責端到端(end-to-end)的傳輸(這裡的"端"指源主機和目的主機)。傳輸層可選擇TCP或UDP協定。TCP是一種面向連接配接的、可靠的協定,有點像打電話,雙方拿起電話互通身份之後就建立了連接配接,然後說話就行了,這邊說的話那邊保證聽得到,并且是按說話的順序聽到的,說完話挂機斷開連接配接。也就是說TCP傳輸的雙方需要首先建立連接配接,之後由TCP協定保證資料收發的可靠性,丢失的資料包自動重發,上層應用程式收到的總是可靠的資料流,通訊之後關閉連接配接。UDP協定不面向連接配接,也不保證可靠性,有點像寄信,寫好信放到郵筒裡,既不能保證信件在郵遞過程中不會丢失,也不能保證信件是按順序寄到目的地的。使用UDP協定的應用程式需要自己完成丢包重發、消息排序等工作。 目的主機收到資料包後,如何經過各層協定棧最後到達應用程式呢?整個過程如下圖所示(該圖出自[TCPIP])。 圖 36.5. Multiplexing過程

TCP/IP協定棧與資料包封裝

  以太網驅動程式首先根據以太網首部中的"上層協定"字段确定該資料幀的有效載荷(payload,指除去協定首部之外實際傳輸的資料)是IP、ARP還是RARP協定的資料報,然後交給相應的協定處理。假如是IP資料報,IP協定再根據IP首部中的"上層協定"字段确定該資料報的有效載荷是TCP、UDP、ICMP還是IGMP,然後交給相應的協定處理。假如是TCP段或UDP段,TCP或UDP協定再根據TCP首部或UDP首部的"端口号"字段确定應該将應用層資料交給哪個使用者程序。IP位址是辨別網絡中不同主機的位址,而端口号就是同一台主機上辨別不同程序的位址,IP位址和端口号合起來辨別網絡中唯一的程序。 注意,雖然IP、ARP和RARP資料報都需要以太網驅動程式來封裝成幀,但是從功能上劃分,ARP和RARP屬于鍊路層,IP屬于網絡層。雖然ICMP、IGMP、TCP、UDP的資料都需要IP協定來封裝成資料報,但是從功能上劃分,ICMP、IGMP與IP同屬于網絡層,TCP和UDP屬于傳輸層。本文對RARP、ICMP、IGMP協定不做進一步介紹,有興趣的讀者可以看參考資料。  

2. 以太網(RFC 894)幀格式   以太網的幀格式如下所示(該圖出自[TCPIP]): 圖 36.6. 以太網幀格式

TCP/IP協定棧與資料包封裝

    其中的源位址和目的位址是指網卡的硬體位址(也叫MAC位址),長度是48位,是在網卡出廠時固化的。用ifconfig指令看一下,"HWaddr 00:15:F2:14:9E:3F"部分就是硬體位址。協定字段有三種值,分别對應IP、ARP、RARP。幀末尾是CRC校驗碼。 以太網幀中的資料長度規定最小46位元組,最大1500位元組,ARP和RARP資料包的長度不夠46位元組,要在後面補填充位。最大值1500稱為以太網的最大傳輸單元(MTU),不同的網絡類型有不同的MTU,如果一個資料包從以太網路由到撥号鍊路上,資料包長度大于撥号鍊路的MTU了,則需要對資料包進行分片(fragmentation)。ifconfig指令的輸出中也有"MTU:1500"。注意,MTU這個概念指資料幀中有效載荷的最大長度,不包括幀首部的長度。     3. ARP資料報格式     在網絡通訊時,源主機的應用程式知道目的主機的IP位址和端口号,卻不知道目的主機的硬體位址,而資料包首先是被網卡接收到再去處理上層協定的,如果接收到的資料包的硬體位址與本機不符,則直接丢棄。是以在通訊前必須獲得目的主機的硬體位址。ARP協定就起到這個作用。源主機發出ARP請求,詢問"IP位址是192.168.0.1的主機的硬體位址是多少",并将這個請求廣播到本地網段(以太網幀首部的硬體位址填FF:FF:FF:FF:FF:FF表示廣播),目的主機接收到廣播的ARP請求,發現其中的IP位址與本機相符,則發送一個ARP應答資料包給源主機,将自己的硬體位址填寫在應答包中。 每台主機都維護一個ARP快取記錄,可以用arp -a指令檢視。緩存表中的表項有過期時間(一般為20分鐘),如果20分鐘内沒有再次使用某個表項,則該表項失效,下次還要發ARP請求來獲得目的主機的硬體位址。想一想,為什麼表項要有過期時間而不是一直有效? ARP資料報的格式如下所示(該圖出自[TCPIP]): 圖 36.7. ARP資料報格式

TCP/IP協定棧與資料包封裝

      注意到源MAC位址、目的MAC位址在以太網首部和ARP請求中各出現一次,對于鍊路層為以太網的情況是多餘的,但如果鍊路層是其它類型的網絡則有可能是必要的。硬體類型指鍊路層網絡類型,1為以太網,協定類型指要轉換的位址類型,0×0800為IP位址,後面兩個位址長度對于以太網位址和IP位址分别為6和4(位元組),op字段為1表示ARP請求,op字段為2表示ARP應答。 下面舉一個具體的例子。 請求幀如下(為了清晰在每行的前面加了位元組計數,每行16個位元組): 以太網首部(14位元組)

0000: ff ff ff ff ff ff 00 05 5d 61 58 a8 08 06

ARP幀(28位元組)

0000: 00 01

0010: 08 00 06 04 00 01 00 05 5d 61 58 a8 c0 a8 00 37

0020: 00 00 00 00 00 00 c0 a8 00 02

填充位(18位元組)

0020: 00 77 31 d2 50 10

0030: fd 78 41 d3 00 00 00 00 00 00 00 00   以太網首部:目的主機采用廣播位址,源主機的MAC位址是00:05:5d:61:58:a8,上層協定類型0×0806表示ARP。 ARP幀:硬體類型0×0001表示以太網,協定類型0×0800表示IP協定,硬體位址(MAC位址)長度為6,協定位址(IP位址)長度為4,op為0×0001表示請求目的主機的MAC位址,源主機MAC位址為00:05:5d:61:58:a8,源主機IP位址為c0 a8 00 37(192.168.0.55),目的主機MAC位址全0待填寫,目的主機IP位址為c0 a8 00 02(192.168.0.2)。 由于以太網規定最小資料長度為46位元組,ARP幀長度隻有28位元組,是以有18位元組填充位,填充位的内容沒有定義,與具體實作相關。 應答幀如下: 以太網首部

0000: 00 05 5d 61 58 a8 00 05 5d a1 b8 40 08 06

ARP幀

0000: 00 01

0010: 08 00 06 04 00 02 00 05 5d a1 b8 40 c0 a8 00 02

0020: 00 05 5d 61 58 a8 c0 a8 00 37

填充位

0020: 00 77 31 d2 50 10

0030: fd 78 41 d3 00 00 00 00 00 00 00 00   以太網首部:目的主機的MAC位址是00:05:5d:61:58:a8,源主機的MAC位址是00:05:5d:a1:b8:40,上層協定類型0×0806表示ARP。 ARP幀:硬體類型0×0001表示以太網,協定類型0×0800表示IP協定,硬體位址(MAC位址)長度為6,協定位址(IP位址)長度為4,op為0×0002表示應答,源主機MAC位址為00:05:5d:a1:b8:40,源主機IP位址為c0 a8 00 02(192.168.0.2),目的主機MAC位址為00:05:5d:61:58:a8,目的主機IP位址為c0 a8 00 37(192.168.0.55)。 思考題:如果源主機和目的主機不在同一網段,ARP請求的廣播幀無法穿過路由器,源主機如何與目的主機通信?     4. IP資料報格式   IP資料報的格式如下(這裡隻讨論IPv4)(該圖出自[TCPIP]): 圖 36.8. IP資料報格式

TCP/IP協定棧與資料包封裝

  IP資料報的首部長度和資料長度都是可變長的,但總是4位元組的整數倍。對于IPv4,4位版本字段是4。4位首部長度的數值是以4位元組為機關的,最小值為5,也就是說首部長度最小是4×5=20位元組,也就是不帶任何選項的IP首部,4位能表示的最大值是15,也就是說首部長度最大是60位元組。8位TOS字段有3個位用來指定IP資料報的優先級(目前已經廢棄不用),還有4個位表示可選的服務類型(最小延遲、最大呑吐量、最大可靠性、最小成本),還有一個位總是0。總長度是整個資料報(包括IP首部和IP層payload)的位元組數。每傳一個IP資料報,16位的辨別加1,可用于分片和重新組裝資料報。3位标志和13位片偏移用于分片。 TTL(Time to live)是這樣用的:源主機為資料包設定一個生存時間,比如64,每過一個路由器就把該值減1,如果減到0就表示路由已經太長了仍然找不到目的主機的網絡,就丢棄該包,是以這個生存時間的機關不是秒,而是跳(hop)。協定字段訓示上層協定是TCP、UDP、ICMP還是IGMP。然後是校驗和,隻校驗IP首部,資料的校驗由更高層協定負責。IPv4的IP位址長度為32位。選項字段的解釋從略。 想一想,前面講了以太網幀中的最小資料長度為46位元組,不足46位元組的要用填充位元組補上,那麼如何界定這46位元組裡前多少個位元組是IP、ARP或RARP資料報而後面是填充位元組?     5. IP位址與路由   IPv4的IP位址長度為4位元組,通常采用點分十進制表示法(dotted decimal representation)例如0xc0a80002表示為192.168.0.2。Internet被各種路由器和網關裝置分隔成很多網段, 為了辨別不同的網段,需要把32位的IP位址劃分成網絡号和主機号兩部分,網絡号相同的各主機位于同一網段,互相間可以直接通信,網絡号不同的主機之間通信則需要通過路由器轉發。 過去曾經提出一種劃分網絡号和主機号的方案,把所有IP位址分為五類,如下圖所示(該圖出自[TCPIP])。 圖 36.9. IP位址類

TCP/IP協定棧與資料包封裝

  A類 0.0.0.0到127.255.255.255

B類 128.0.0.0到191.255.255.255

C類 192.0.0.0到223.255.255.255

D類 224.0.0.0到239.255.255.255

E類 240.0.0.0到247.255.255.255   一個A類網絡可容納的位址數量最大,一個B類網絡的位址數量是65536,一個C類網絡的位址數量是256。D類位址用作多點傳播位址,E類位址保留未用。 随着Internet的飛速發展,這種劃分方案的局限性很快顯現出來,大多數組織都申請B類網絡位址,導緻B類位址很快就配置設定完了,而A類卻浪費了大量位址。這種方式對網絡的劃分是flat的而不是層級結構(hierarchical)的,Internet上的每個路由器都必須掌握所有網絡的資訊,随着大量C類網絡的出現,路由器需要檢索的路由表越來越龐大,負擔越來越重。 針對這種情況提出了新的劃分方案,稱為 CIDR(Classless Interdomain Routing)。 網絡号和主機号的劃分需要用一個額外的子網路遮罩(subnet mask)來表示,而不能由IP位址本身的數值決定,也就是說,網絡号和主機号的劃分與這個IP位址是A類、B類還是C類無關,是以稱為Classless的。這樣,多個子網就可以彙總(summarize)成一個Internet上的網絡,例如,有8個站點都申請了C類網絡,本來網絡号是24位的,但是這8個站點通過同一個ISP(Internet service provider)連到Internet上,它們網絡号的高21位是相同的,隻有低三位不同,這8個站點就可以彙總,在Internet上隻需要一個路由表項,資料包通過Internet上的路由器到達ISP,然後在ISP這邊再通過次級的路由器選路到某個站點。 下面舉兩個例子: 表 36.1. 劃分子網的例子1         IP位址 140.252.20.68 8C FC 14 44 子網路遮罩 255.255.255.0 FF FF FF 00 網絡号 140.252.20.0 8C FC 14 00 子網位址範圍 140.252.20.0~140.252.20.255   表 36.2. 劃分子網的例子2

  IP位址 140.252.20.68 8C FC 14 44 子網路遮罩 255.255.255.240 FF FF FF F0 網絡号 140.252.20.64 8C FC 14 40 子網位址範圍 140.252.20.64~140.252.20.79   可見,IP位址與子網路遮罩做與運算可以得到網絡号,主機号從全0到全1就是子網的位址範圍。IP位址和子網路遮罩還有一種更簡潔的表示方法,例如140.252.20.68/24,表示IP位址為140.252.20.68,子網路遮罩的高24位是1,也就是255.255.255.0。 如果一個組織内部組建區域網路,IP位址隻用于區域網路内的通信,而不直接連到Internet上,理論上使用任意的IP位址都可以,但是RFC 1918規定了用于組建區域網路的私有IP位址,這些位址不會出現在Internet上,如下表所示。 10.*,前8位是網絡号,共16,777,216個位址 172.16.*到172.31.*,前12位是網絡号,共1,048,576個位址 192.168.*,前16位是網絡号,共65,536個位址 使用私有IP位址的區域網路主機雖然沒有Internet的IP位址,但也可以通過代理伺服器或NAT(網絡位址轉換)等技術連到Internet上。 除了私有IP位址之外,還有幾種特殊的IP位址。127.*的IP位址用于本機環回(loop back)測試,通常是127.0.0.1。loopback是 系統中一種特殊的網絡裝置,如果發送資料包的目的位址是環回位址,或者與本機其它網絡裝置的IP位址相同,則資料包不會發送到網絡媒體上,而是通過環回裝置再發回給上層協定和應用程式,主要用于測試。如下圖所示(該圖出自[TCPIP])。 圖 36.10. loopback裝置

TCP/IP協定棧與資料包封裝

      還有一些不能用作主機IP位址的特殊位址: 目的位址為255.255.255.255,表示本網絡内部廣播,路由器不轉發這樣的廣播資料包。 主機号全為0的位址隻表示網絡而不能表示某個主機,如192.168.10.0(假設子網路遮罩為255.255.255.0)。 目的位址的主機号為全1,表示廣播至某個網絡的所有主機,例如目的位址192.168.10.255表示廣播至192.168.10.0網絡(假設子網路遮罩為255.255.255.0)。 下面介紹路由的過程,首先正式定義幾個名詞: 路由(名詞) 資料包從源位址到目的位址所經過的路徑,由一系列路由節點組成。 路由(動詞) 某個路由節點為資料報選擇投遞方向的選路過程。 路由節點: 一個具有路由能力的主機或路由器,它維護一張路由表,通過查詢路由表來決定向哪個接口發送資料包。 接口: 路由節點與某個網絡相連的網卡接口。 路由表: 由很多路由條目組成,每個條目都指明去往某個網絡的資料包應該經由哪個接口發送,其中最後一條是預設路由條目。 路由條目: 路由表中的一行,每個條目主要由目的網絡位址、子網路遮罩、下一跳位址、發送接口四部分組成,如果要發送的資料包的目的網絡位址比對路由表中的某一行,就按規定的接口發送到下一跳位址。 預設路由條目: 路由表中的最後一行,主要由下一跳位址和發送接口兩部分組成,當目的位址與路由表中其它行都不比對時,就按預設路由條目規定的接口發送到下一跳位址。

假設某主機上的網絡接口配置和路由表如下: $ ifconfig

eth0  Link encap:Ethernet  HWaddr 00:0C:29:C2:8D:7E

  inet addr:192.168.10.223  Bcast:192.168.10.255  Mask:255.255.255.0

  UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

  RX packets:0 errors:0 dropped:0 overruns:0 frame:0

  TX packets:10 errors:0 dropped:0 overruns:0 carrier:0

  collisions:0 txqueuelen:100

  RX bytes:0 (0.0 b)  TX bytes:420 (420.0 b)

  Interrupt:10 Base address:0x10a0 eth1  Link encap:Ethernet  HWaddr 00:0C:29:C2:8D:88

  inet addr:192.168.56.136  Bcast:192.168.56.255  Mask:255.255.255.0

  UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

  RX packets:603 errors:0 dropped:0 overruns:0 frame:0

  TX packets:110 errors:0 dropped:0 overruns:0 carrier:0

  collisions:0 txqueuelen:100

  RX bytes:55551 (54.2 Kb)  TX bytes:7601 (7.4 Kb)

  Interrupt:9 Base address:0x10c0 lo  Link encap:Local Loopback

  inet addr:127.0.0.1  Mask:255.0.0.0

  UP LOOPBACK RUNNING  MTU:16436  Metric:1

  RX packets:37 errors:0 dropped:0 overruns:0 frame:0

  TX packets:37 errors:0 dropped:0 overruns:0 carrier:0

  collisions:0 txqueuelen:0

  RX bytes:3020 (2.9 Kb)  TX bytes:3020 (2.9 Kb)

$ route

Kernel IP routing table

Destination  Gateway  Genmask  Flags Metric Ref  Use Iface

192.168.10.0  *  255.255.255.0  U  0  0  0 eth0

192.168.56.0  *  255.255.255.0  U  0  0  0 eth1

127.0.0.0  *  255.0.0.0  U  0  0  0 lo

default  192.168.10.1  0.0.0.0  UG  0  0  0 eth0 這台主機有兩個網絡接口,一個網絡接口連到192.168.10.0/24網絡,另一個網絡接口連到192.168.56.0/24網絡。路由表的Destination是目的網絡位址,Genmask是子網路遮罩,Gateway是下一跳位址,Iface是發送接口,Flags中的U标志表示此條目有效(可以禁用某些條目),G标志表示此條目的下一跳位址是某個路由器的位址,沒有G标志的條目表示目的網絡位址是與本機接口直接相連的網絡,不必經路由器轉發,是以下一跳位址處記為*号。 如果要發送的資料包的目的位址是192.168.56.3,跟第一行的子網路遮罩做與運算得到192.168.56.0,與第一行的目的網絡位址不符,再跟第二行的子網路遮罩做與運算得到192.168.56.0,正是第二行的目的網絡位址,是以從eth1接口發送出去,由于192.168.56.0/24正是與eth1接口直接相連的網絡,是以可以直接發到目的主機,不需要經路由器轉發。 如果要發送的資料包的目的位址是202.10.1.2,跟前三行路由表條目都不比對,那麼就要按預設路由條目,從eth0接口發出去,首先發往192.168.10.1路由器,再讓路由器根據它的路由表決定下一跳位址。     6. UDP段格式   下圖是UDP的段格式(該圖出自[TCPIP])。 圖 36.11. UDP段格式

TCP/IP協定棧與資料包封裝

      下面分析一幀基于UDP的TFTP協定幀。 以太網首部

0000: 00 05 5d 67 d0 b1 00 05 5d 61 58 a8 08 00

IP首部

0000: 45 00

0010: 00 53 93 25 00 00 80 11 25 ec c0 a8 00 37 c0 a8

0020: 00 01

UDP首部

0020: 05 d4 00 45 00 3f ac 40

TFTP協定

0020: 00 01 ‘c”:”\”q’

0030: ‘w”e”r”q”.”q”w”e’00 ‘n”e”t”a’’s”c”i’

0040: ‘i’00 ‘b”l”k’’s”i”z”e’00 ‘5”1”2′00 ‘t”i’

0050: ‘m”e”o”u”t’00 ‘1”0′00 ‘t’’s”i”z”e’00 ‘0′

0060: 00   以太網首部:源MAC位址是00:05:5d:61:58:a8,目的MAC位址是00:05:5d:67:d0:b1,上層協定類型0×0800表示IP。 IP首部:每一個位元組0×45包含4位版本号和4位首部長度,版本号為4,即IPv4,首部長度為5,說明IP首部不帶有選項字段。服務類型為0,沒有使用服務。16位總長度字段(包括IP首部和IP層payload的長度)為0×0053,即83位元組,加上以太網首部14位元組可知整個幀長度是97位元組。IP報辨別是0×9325,标志字段和片偏移字段設定為0×0000,就是DF=0允許分片,MF=0此資料報沒有更多分片,沒有分片偏移。TTL是0×80,也就是128。上層協定0×11表示UDP協定。IP首部校驗和為0×25ec,源主機IP是c0 a8 00 37(192.168.0.55),目的主機IP是c0 a8 00 01(192.168.0.1)。 UDP首部:源端口号0×05d4(1492)是用戶端的端口号,目的端口号0×0045(69)是TFTP服務的well-known端口号。UDP報長度為0×003f,即63位元組,包括UDP首部和UDP層payload的長度。UDP首部和UDP層payload的校驗和為0xac40。 TFTP是基于文本的協定,各字段之間用位元組0分隔,開頭的00 01表示請求讀取一個檔案,接下來的各字段是: c:\qwerq.qwe

netascii

blksize 512

timeout 10

tsize 0   一般的網絡通信都是像TFTP協定這樣,通信的雙方分别是用戶端和伺服器,用戶端主動發起請求(上面的例子就是用戶端發起的請求幀),而伺服器被動地等待、接收和應答請求。 用戶端的IP位址和端口号唯一辨別了該主機上的TFTP用戶端程序,伺服器的IP位址和端口号唯一辨別了該主機上的TFTP服務程序,由于用戶端是主動發起請求的一方,它必須知道伺服器的IP位址和TFTP服務程序的端口号,是以,一些常見的網絡協定有預設的伺服器端口,例如HTTP服務預設TCP協定的80端口,FTP服務預設TCP協定的21端口,TFTP服務預設UDP協定的69端口(如上例所示)。在使用用戶端程式時,必須指定伺服器的主機名或IP位址,如果不明确指定端口号則采用預設端口,請讀者查閱ftp、tftp等程式的man page了解如何指定端口号。/etc/services中列出了所有well-known的服務端口和對應的傳輸層協定,這是由IANA(Internet Assigned Numbers Authority)規定的,其中有些服務既可以用TCP也可以用UDP,為了清晰,IANA規定這樣的服務采用相同的TCP或UDP預設端口号,而另外一些TCP和UDP的相同端口号卻對應不同的服務。 很多服務有well-known的端口号,然而用戶端程式的端口号卻不必是well-known的,往往是每次運作用戶端程式時由系統自動配置設定一個空閑的端口号,用完就釋放掉,稱為ephemeral的端口号,想想這是為什麼。 前面提過,UDP協定不面向連接配接,也不保證傳輸的可靠性,例如: 發送端的UDP協定層隻管把應用層傳來的資料封裝成段交給IP協定層就算完成任務了,如果因為網絡故障該段無法發到對方,UDP協定層也不會給應用層傳回任何錯誤資訊。 接收端的UDP協定層隻管把收到的資料根據端口号交給相應的應用程式就算完成任務了,如果發送端發來多個資料包并且在網絡上經過不同的路由,到達接收端時順序已經錯亂了,UDP協定層也不保證按發送時的順序交給應用層。 通常接收端的UDP協定層将收到的資料放在一個固定大小的緩沖區中等待應用程式來提取和處理,如果應用程式提取和處理的速度很慢,而發送端發送的速度很快,就會丢失資料包,UDP協定層并不報告這種錯誤。 是以,使用UDP協定的應用程式必須考慮到這些可能的問題并實作适當的解決方案,例如等待應答、逾時重發、為資料包編号、流量控制等。一般使用UDP協定的應用程式實作都比較簡單,隻是發送一些對可靠性要求不高的消息,而不發送大量的資料。例如,基于UDP的TFTP協定一般隻用于傳送小檔案(是以才叫trivial的ftp),而基于TCP的FTP協定适用于各種檔案的傳輸。下面看TCP協定如何用面向連接配接的服務來代替應用程式解決傳輸的可靠性問題。   7. TCP協定   7.1. 段格式     TCP的段格式如下圖所示(該圖出自[TCPIP])。 圖 36.12. TCP段格式

TCP/IP協定棧與資料包封裝

      和UDP協定一樣也有源端口号和目的端口号,通訊的雙方由IP位址和端口号辨別。32位序号、32位确認序号、視窗大小稍後詳細解釋。4位首部長度和IP協定頭類似,表示TCP協定頭的長度,以4位元組為機關,是以TCP協定頭最長可以是4×15=60位元組,如果沒有選項字段,TCP協定頭最短20位元組。URG、ACK、PSH、RST、SYN、FIN是六個控制位,本節稍後将解釋SYN、ACK、FIN、RST四個位,其它位的解釋從略。16位檢驗和将TCP協定頭和資料都計算在内。緊急指針和各種選項的解釋從略。   7.2. 通訊時序  下圖是一次TCP通訊的時序圖。 圖 36.13. TCP連接配接建立斷開

TCP/IP協定棧與資料包封裝

      在這個例子中,首先用戶端主動發起連接配接、發送請求,然後伺服器端響應請求,然後用戶端主動關閉連接配接。兩條豎線表示通訊的兩端,從上到下表示時間的先後順序,注意,資料從一端傳到網絡的另一端也需要時間,是以圖中的箭頭都是斜的。雙方發送的段按時間順序編号為1-10,各段中的主要資訊在箭頭上标出,例如段2的箭頭上标着SYN, 8000(0), ACK 1001, <mss 1024>,表示該段中的SYN位置1,32位序号是8000,該段不攜帶有效載荷(資料位元組數為0),ACK位置1,32位确認序号是1001,帶有一個mss選項值為1024。 建立連接配接的過程: 用戶端發出段1,SYN位表示連接配接請求。序号是1000,這個序号在網絡通訊中用作臨時的位址,每發一個資料位元組,這個序号要加1,這樣在接收端可以根據序号排出資料包的正确順序,也可以發現丢包的情況,另外,規定SYN位和FIN位也要占一個序号,這次雖然沒發資料,但是由于發了SYN位,是以下次再發送應該用序号1001。mss表示最大段尺寸,如果一個段太大,封裝成幀後超過了鍊路層的最大幀長度,就必須在IP層分片,為了避免這種情況,用戶端聲明自己的最大段尺寸,建議伺服器端發來的段不要超過這個長度。 伺服器發出段2,也帶有SYN位,同時置ACK位表示确認,确認序号是1001,表示"我接收到序号1000及其以前所有的段,請你下次發送序号為1001的段",也就是應答了用戶端的連接配接請求,同時也給用戶端發出一個連接配接請求,同時聲明最大尺寸為1024。 用戶端發出段3,對伺服器的連接配接請求進行應答,确認序号是8001。 在這個過程中,用戶端和伺服器分别給對方發了連接配接請求,也應答了對方的連接配接請求,其中伺服器的請求和應答在一個段中發出,是以一共有三個段用于建立連接配接,稱為”’三方握手(three-way-handshake)”’。在建立連接配接的同時,雙方協商了一些資訊,例如雙方發送序号的初始值、最大段尺寸等。 在TCP通訊中,如果一方收到另一方發來的段,讀出其中的目的端口号,發現本機并沒有任何程序使用這個端口,就會應答一個包含RST位的段給另一方。例如,伺服器并沒有任何程序使用8080端口,我們卻用telnet用戶端去連接配接它,伺服器收到用戶端發來的SYN段就會應答一個RST段,用戶端的telnet程式收到RST段後報告錯誤Connection refused: $ telnet 192.168.0.200 8080

Trying 192.168.0.200...

telnet: Unable to connect to remote host: Connection refused 資料傳輸的過程: 用戶端發出段4,包含從序号1001開始的20個位元組資料。 伺服器發出段5,确認序号為1021,對序号為1001-1020的資料表示确認收到,同時請求發送序号1021開始的資料,伺服器在應答的同時也向用戶端發送從序号8001開始的10個位元組資料,這稱為piggyback。 用戶端發出段6,對伺服器發來的序号為8001-8010的資料表示确認收到,請求發送序号8011開始的資料。 在資料傳輸過程中,ACK和确認序号是非常重要的,應用程式交給TCP協定發送的資料會暫存在TCP層的發送緩沖區中,發出資料包給對方之後,隻有收到對方應答的ACK段才知道該資料包确實發到了對方,可以從發送緩沖區中釋放掉了,如果因為網絡故障丢失了資料包或者丢失了對方發回的ACK段,經過等待逾時後TCP協定自動将發送緩沖區中的資料包重發。 這個例子隻描述了最簡單的一問一答的情景,實際的TCP資料傳輸過程可以收發很多資料段,雖然典型的情景是用戶端主動請求伺服器被動應答,但也不是必須如此,事實上TCP協定為應用層提供了全雙工(full-duplex)的服務,雙方都可以 主動甚至同時給對方發送資料。 如果通訊過程隻能采用一問一答的方式,收和發兩個方向不能同時傳輸,在同一時間隻允許一個方向的資料傳輸,則稱為”’半雙工(half-duplex)”’,假設某種面向連接配接的協定是半雙工的,則隻需要一套序号就夠了,不需要通訊雙方各自維護一套序号,想一想為什麼。 關閉連接配接的過程: 用戶端發出段7,FIN位表示關閉連接配接的請求。 伺服器發出段8,應答用戶端的關閉連接配接請求。 伺服器發出段9,其中也包含FIN位,向用戶端發送關閉連接配接請求。 用戶端發出段10,應答伺服器的關閉連接配接請求。 建立連接配接的過程是三方握手,而關閉連接配接通常需要4個段,伺服器的應答和關閉連接配接請求通常不合并在一個段中,因為有連接配接半關閉的情況,這種情況下用戶端關閉連接配接之後就不能再發送資料給伺服器了,但是伺服器還可以發送資料給用戶端,直到伺服器也關閉連接配接為止,稍後會看到這樣的例子。   7.3. 流量控制  介紹UDP時我們描述了這樣的問題:如果發送端發送的速度較快,接收端接收到資料後處理的速度較慢,而接收緩沖區的大小是固定的,就會丢失資料。TCP協定通過”’滑動視窗(Sliding Window)”’機制解決這一問題。看下圖的通訊過程。 圖 36.14. 滑動視窗

TCP/IP協定棧與資料包封裝

      發送端發起連接配接,聲明最大段尺寸是1460,初始序号是0,視窗大小是4K,表示"我的接收緩沖區還有4K位元組空閑,你發的資料不要超過4K"。接收端應答連接配接請求,聲明最大段尺寸是1024,初始序号是8000,視窗大小是6K。發送端應答,三方握手結束。 發送端發出段4-9,每個段帶1K的資料,發送端根據視窗大小知道接收端的緩沖區滿了,是以停止發送資料。 接收端的應用程式提走2K資料,接收緩沖區又有了2K空閑,接收端發出段10,在應答已收到6K資料的同時聲明視窗大小為2K。 接收端的應用程式又提走2K資料,接收緩沖區有4K空閑,接收端發出段11,重新聲明視窗大小為4K。 發送端發出段12-13,每個段帶2K資料,段13同時還包含FIN位。 接收端應答接收到的2K資料(6145-8192),再加上FIN位占一個序号8193,是以應答序号是8194,連接配接處于半關閉狀态,接收端同時聲明視窗大小為2K。 接收端的應用程式提走2K資料,接收端重新聲明視窗大小為4K。 接收端的應用程式提走剩下的2K資料,接收緩沖區全空,接收端重新聲明視窗大小為6K。 接收端的應用程式在提走全部資料後,決定關閉連接配接,發出段17包含FIN位,發送端應答,連接配接完全關閉。 上圖在接收端用小方塊表示1K資料,實心的小方塊表示已接收到的資料,虛線框表示接收緩沖區,是以套在虛線框中的空心小方塊表示視窗大小,從圖中可以看出,随着應用程式提走資料,虛線框是向右滑動的,是以稱為滑動視窗。 從這個例子還可以看出,發送端是一K一K地發送資料,而接收端的應用程式可以兩K兩K地提走資料,當然也有可能一次提走3K或6K資料,或者一次隻提走幾個位元組的資料,也就是說,應用程式所看到的資料是一個整體,或說是一個流(stream),在底層通訊中這些資料可能被拆成很多資料包來發送,但是一個資料包有多少位元組對應用程式是不可見的,是以TCP協定是面向流的協定。而UDP是面向消息的協定,每個UDP段都是一條消息,應用程式必須以消息為機關提取資料,不能一次提取任意位元組的資料,這一點和TCP是很不同的。

繼續閱讀