標籤:
開始學習網路編程的經典《UNIX網路編程》(第3版)作為研究生階段的副本練習吧,厚厚一本書,希望能堅持看下去,堅持做些筆記。
1.TCP/IP協議概述IPv4
網際協議版本4(Internet Protocol version 4),32位地址,為TCP、UDP、SCTP、ICMP和IGMP提供分組遞送服務。
IPv6
網際協議版本6(Internet Protocol version 6)。128位地址,為TCP、UDP、SCTP和ICMPv6提供分組遞送服務。
TCP
傳輸控制通訊協定(Transmission Control Protocol)。連線導向的傳輸層協議,提供可靠的全雙工系統位元組流,使用流通訊端(stream socket)。
UDP
使用者資料包通訊協定(User Datagram Protocol)。UDP是一個不需連線的傳輸層協議,使用資料通訊端(datgram socket)。
SCTP
流量控制傳輸協議(Stream Control Transmission Protocol)。是可靠全雙工系統關聯的連線導向的傳輸層協議。SCTP是多宿的,每個關聯的兩端均涉及一組IP地址和一個連接埠號碼。這裡多宿的概念簡單理解就是多個網卡。
ICMP協議
網際控制訊息協議(Internet Control Message Protocol)。ICMP處理在路由器和主機之間流通的錯誤和控制資訊。這些訊息由TCP/IP網路支援軟體本身(而不是使用者進程)產生和處理,例如ping和traceroute使用ICMP。
IGMP協議
網際組管理協議(Internet Group Management Protocol)。IGMP用於多播。
ARP(Address Resolution Protocol)和RARP(Reverse Address Resolution Protocol)
ARP位址解析通訊協定把一個IPV4映射成一個硬體地址(乙太網路地址)。RARP反向位址解析通訊協定把一個硬體地址映射成一個IPv4地址。
2.使用者資料包通訊協定(UDP)
UDP是無串連不可靠的傳輸層協議,著些主要體現在:
當使用者進程往一個UDP通訊端寫入訊息,訊息隨後被封裝到一個UDP資料報(每個資料報都會有一個長度記錄被接收端應用程式擷取),進而又被封裝到一個IP資料報,然後發往目的地,但是:UDP不保證資料報會到達其最終目的地,不保證各個資料報到達的先後順序,也不保證資料報只到達一次。
3.傳輸控制通訊協定(TCP)TCP嚮應用程式提供連線導向的可靠性服務
連線導向體現在:TCP用戶端要首先與某個伺服器建立一個串連,然後再誇該串連交換資料,最後終止串連。
可靠性體現在:TCP不保證資料一定會被對方端點接收,它提供的是資料的可靠遞送(等待確認並自動重傳)和故障的可靠通知(放棄重傳或中斷串連)。在數次重傳失敗後,TCP才會放棄,如此在嘗試發送資料所花的時間一般為4~10分鐘。
TCP具有的一些能力
-
可以動態估算客戶和伺服器之間的往返時間(round-trip time RTT),以便知道等待一個確認需要多少時間。例如RTT在區域網路中幾毫秒,在廣域網路則要數秒。
-
TCP對所發的資料進行排序:即在每個分節(TCP傳遞給IP的資料單元)的內部給每個位元組關聯一個序號,這就可以保證:在應用接收資料之前對非順序到達的資料進行排序、並且對對端的重複資料進行丟棄。
-
TCP提供流量控制(flow control),流量控制確保發送端發送的資料不會使得接收端緩衝區溢位:當發送資料太快,而接收端來不及接收時,為了保證資料不丟失,必須協調好雙方通訊的節奏,通告視窗就起到了這樣的作用:當接收來自發送端的資料時,視窗大小減小,當接收端從緩衝區讀走資料時,視窗就變大;當視窗為0時,說明TCP對應某個通訊端的緩衝區已滿,此時它必須等待對端從緩衝區讀取資料和不為0的通告視窗訊息的到來。
-
TCP串連是全雙工系統的(UDP也可以是全雙工系統),也就是說在一個給定的串連上,應用可以在任何時刻在近處的兩個方向上既發送資料又接收資料,需要的話也可以改成單工串連。
4.流量控制傳輸協議(SCTP)
這個協議以前沒聽過,今天也學習一蛤。
SCTP支援多宿,與TCP相比提供兩個IP地址之間的通訊,SCTP可以提供兩個系統之間的通訊:一個端點可以有冗餘的網路連接,每個網路又可以有各自接入網際網路基礎設施的串連,這樣,乳溝某個網路或者通路發生故障,SCTP可以切換到使用已與該關聯相關的另一個地址來規避故障。
SCTP是面向訊息的。它提供各個記錄的按序遞送服務,與UDP記錄資料報長度一樣,SCTP也會寫入每條記錄的長度隨資料一道傳遞給接收端應用。
PS:UDP是面向資料報,TCP是面向位元組流的。
與TCP不同的是,當TCP位元組丟失,將阻塞其後資料的遞送,而SCTP則不會阻塞。
5.TCP的串連和終止三路握手
我們知道TCP串連要經過三路握手,實際將發生下面這些情況:
- 伺服器server端通過socket(建立通訊端)、bind(綁定通訊端)、listen(監聽通訊端)這三個過程完成,被稱之為被動開啟(passive open)
- 用戶端client通過調用connect發起主動開啟(active open)去向一個固定IP和固定連接埠號碼的伺服器發起串連。這導致客戶TCP發送一個SYN分節來告訴伺服器將在接下來的發送資料時的初始序號。SYN(Synchronous)是建立串連時使用的握手訊號,通常SYN不攜帶資料只有一些前序。
- 伺服器要給用戶端回複一個ACK和一個SYN,ACK用來確認客戶的SYN,SYN包含伺服器在該串連中發送的資料的初始序號。
- 最後客戶必須確認第3點中伺服器發送的SYN。
這就是三路握手的過程,所謂的三路握手,指的是這種伺服器與用戶端之間的交換至少需要3個分組。
根據圖示,為什麼客戶發送SYNJ時(客戶的初始序號為J),伺服器要回應$ACK_{J+1}(用戶端期待的下一個序號)?原因很簡單,因為SYN所在位元組本身也是一個序號空間。
書中給出一個例子來說明TCP建立一次串連:
伺服器端:
socket建立通訊端=買一個手機
bind綁定通訊端=辦一張卡並把號碼告訴別人
listen監聽通訊端=把手機開啟為響鈴模式
accept從等待串連隊列中抽取一個串連,並建立一個新的通訊端返回客戶的標識=來電顯示
用戶端:
connect=撥打指定號碼的電話
TCP選項
每個SYN可以有一些TCP選項,可以在待建立的串連中起到配置作用:
- MSS選項:MSS=Maximum Segment Size,即最大分節大小,發送端TCP使用接收端的MSS值作為所發送分節的最大大小。
- 視窗規模選項:TCP使用滑動視窗進行流量控制,最大視窗大小是65535,這是因為TCP首部中配置視窗大小的相應欄位佔16位。
- 時間戳記選項:這個選項針對於高速網路,以防止由失而複得的分組可能造成的資料損毀。
TCP串連終止
TCP建立一個串連需要3個分節,而終止一個串連需要4個分節,具體過程如下:
- 用戶端首先調用close關閉通訊端(主動關閉),該端的TCP會發送一個FIN分節。
- 伺服器收到FIN後首先會發送一個ACK確認,同時會傳遞給本端接收應用進程一個檔案結束符(EOF),這個結束符放在接收到的資料的緩衝隊列的隊尾,由於FIN的收到,也不會再收到額外資料了。
- 一段時間後,接收到檔案結束符的應用調用close關閉通訊端,此時服務端TCP也會發送一個FIN。
- 主動發起串連的一端收到FIN後會發送一個ACK作為確認。
每個方向都需要有一個ACK和一個FIN,所以說通常是4個位元組。:
上述舉例是用戶端主動發起關閉(通常情況下是這樣),實際上在某些協議(例如HTTP/1.0)可以由伺服器執行主動關閉,事實上,在書中第1章給出的擷取時間的demo中,都是伺服器主動中斷連線。
半關閉的概念:當伺服器收到FIN之後,在它向用戶端回應一個ACK和發送一個FIN之間(上述2,3步驟)是可以有資料流的,使用shutdown函數。
TCP狀態轉換圖
TCP為一個串連定義了11種狀態。這裡就直接貼出電子書中截出的圖。
圖中可以看出,用戶端和伺服器都對應自己的狀態轉移圖,並且此處不考慮用戶端和伺服器同時開啟和同時關閉的情況,這種情況下,網路中會出現SYN或FIN交錯的情況。
可以使用netstat工具去監視狀態的變化情況。
觀察分組
書中給出了一個完整的TCP串連所發生的封包交換情況,這裡也貼出圖來:
過程很簡單:客戶服務器建立三向交握串連->客戶與伺服器進行資料互動->客戶主動關閉串連
這裡我比較在意的是兩個MSS值的定義,圖中箭頭所示,網上看了不少資料得出如下結論:
- IP資料包包頭和TCP資料包包頭分別是20bytes和20bytes
- MTU(傳輸單元最大值)由硬體特性決定,乙太網路為例,其MTU=1500bytes
- MTU=IP前序+TCP前序+MSS
- 如果IP資料報大於MTU則IP報文就要分區傳輸,而TCP報文如果超過MSS,則TCP進行分段傳輸。
- 在IP不分區的前提下計算的得到MSS=1500-20-20=1460bytes
- Internet上標準的MTU是576bytes(MSS=576-20-20=536)
根據上述結論,就理解了書中1460和536的設定了。另外,伺服器對客戶請求的確認是伴隨其應答發送的,這種做法被稱作捎帶(piggybacking),它通常在伺服器處理請求併產生應答的時間少於200ms發生。
單從書中例子給出的交換來說,除了資料請求和資料應答,其餘至少8個分節都是TCP的額外開銷(除了建立串連和終止串連的7個分節外,還包括資料應答ACK)
SYN J
SYN K、 ACK J+1
ACK K+1
應答ACK
FIN M
ACK M+1
FIN N
ACK N+1
6.TIME_WAIT狀態
書中單獨拉出來作為一個小節出來,想必很重要吧。
首先,TIME_WAIT狀態的停留時間長度是最長分節生命期(Maximum Segment Lifetime,MSL)的兩倍,有時候稱之為2MSL。
TIME_WAIT狀態的存在有兩個理由:
- 可靠地實現TCP全雙工系統串連的終止
- 允許老的重複分節在網路中消逝
第1個理由很好理解:假設伺服器端發送FIN N,而用戶端的第一個ACK N+1因為某些原因丟失了,這個時候伺服器久久沒有收到ACK就會逾時重傳一個FIN N,那麼此時用戶端必須維護當前的狀態資訊,這樣它才能重新發送那個最終的ACK N+1。
更廣義的說法:如果串連雙方的某一端發起了主動關閉串連,那麼它最終會進入TIME_WAIT狀態,因為如果出現異常最終重傳的ACK就是由主動發起關閉串連的那一端發送的。
第2個理由就有點繞口了,我們假設同一個IP和連接埠之間有一個TCP串連,我們關閉這個串連,過一段時間後在相同的IP地址和連接埠號碼之間建立另一個串連。後一個串連成為前一個串連的化身,因為他們的IP地址和連接埠號碼相同。TCP防止某個老的重複的分組,在該串連終止後再現,從而被誤解成屬於同一串連的某個化身。為了做到這一點,TCP將不給處於TIME_WAIT狀態的串連發起新的化身,(這句話我的理解是,如果在串連雙方,某一端進入了TIME_WAIT狀態,那麼,TCP將不會再在串連雙方所對應的IP和連接埠發起串連,即所謂的化身,此時這個即將斷開的串連中還有多的重複的分組)。既然TIME_WAIT狀態期間是MSL的兩倍,那麼這個時間足以讓某個方向上的分組最多存活MSL秒就被丟棄,另一個方向上的應答最多存活MSL也被丟棄。
總結這兩個理由可以歸結為兩句話:
**1. 萬一在最中確認串連中斷時伺服器的ACK回應丟失怎麼辦,這樣就必須再次重傳FIN。
2. 萬一在極短的時間內從新有一個相同通訊端串連建立怎麼辦,這樣就必須處理完上一次資料。**
7.SCTP簡介
SCTP也是連線導向的,因而也有關聯的建立和終止的握手過程。與tcp不同的是,建立串連需要4個分節(四路握手),關閉串連需要3個分節。SCTP的思路握手跟TCP的三路握手類似,差別在於作為SCTP整體一部分的cookie的產生,這個cookie包含了伺服器IP地址清單、初始序號等內容。SCTP重要程度次於TCP,這裡僅僅貼出書中。
四路握手示意
關聯終止示意
SCTP中的封包交換
8.連接埠號碼
多個進程可能同時使用傳輸層協議,連接埠號碼(16位整數)用來區分這些進程。
眾所周知的連接埠號碼:0-1023
已登記連接埠號碼:1024-49151
動態或者私用連接埠:49152-65535
常用連接埠號碼:
| 協議 |
連接埠號碼 |
| HTTP協議Proxy 伺服器常用連接埠號碼 |
80、8080、3128、8081、9080 |
| FTP(檔案傳輸)協議Proxy 伺服器常用連接埠號碼 |
21/TCP |
| TFTP(Trivial File Transfer Protocol ),預設的連接埠號碼 |
69/UDP |
| SMTP Simple Mail Transfer Protocol (E-mail),預設的連接埠號碼 |
25/TCP |
| SSH(安全登入)、SCP(檔案傳輸)、連接埠重新導向,預設的連接埠號碼 |
22/TCP |
另外,客戶通常使用短期存貨的臨時連接埠號碼,這些連接埠號碼由傳輸層協議自動賦予客戶。
通訊端與通訊端對
通訊端:標識每個端點的兩個值IP地址和連接埠號碼
通訊端對:定義一個TCP串連的兩個端點的四元組{本地IP:本地連接埠號碼,外地IP:外地連接埠號碼}
並發伺服器中主伺服器迴圈派生子進程來處理新的串連。
TCP通過通訊端對來區分串連,比如說:
在伺服器端,父進程的監聽通訊端:{:21,:*}
fork子進程1的已串連通訊端:{本地ip:21,外地ip1:外地連接埠號碼1}
fork子進程2的已串連通訊端:{本地ip:21,外地ip2:外地連接埠號碼2}
9.緩衝區大小限制
知道下面一些概念:
1. ipv4資料報最大大小是65535位元組,包括ipv4的首部,這個原因是因為在IPV4前序中用以表示其總長度的欄位只有16位。ipv6是65575位元組=65535+40,40表示ipv6首部。(ipv6中淨長度不包括首部)
2. MTU在上文中提到,由鏈路層的硬體規定,譬如說乙太網路的MTU是1500位元組,IPv4要求的最小鏈路MTU是68位元組。IPV6要求最小鏈路MTU是1280位元組。
3. 關於分區的說法,當一個IP資料報從某個介面出去的時候,如果它的大小超過相應鏈路的MTU,則IPv4和IPv6將執行分區(fragmentation),在Windows下,可以通過ping命令來查看原生MTU大小,例如:
ping -l 1800 -f www.baidu.com
-f選項給IPv4首部設定不分區(dont fragment)即DF位,而-l選項表示向目標主機發送多少位元組的資料,雖然理論上來說最大可以是65535位元組,然而在DOS下ping -l最大是65500位元組(因為windows的漏洞所致),好了這些都不是重點。通過ping的方式,我們可以知道本機設定的MTU的大小(一般小於1500),當我們向目標主機發送大於MTU的資料並且強制設定不分區,系統就會提示錯誤:
需要拆分資料包但是設定DF
意思顯而易見就是說,你要發送這麼多資料超過了我MTU的大小現在必須要分區了,可是你卻又設定不分區。
10.TCP&UDP輸出TCP
當某個應用進程寫資料到一個TCP通訊端中時將經過下面步驟:
1.每個TCP通訊端有一個發送緩衝區,我們可以使用SO_SNDBUF通訊端選項來更改緩衝區大小。
2.當某個應用進程調用write時,核心從該應用進程的緩衝區複製所有資料到所寫通訊端的發送緩衝區。
3.write函數是阻塞調用,也就是說,當通訊端的發送緩衝區大小小於應用進程的資料時,應用進程將被投入休眠,直到應用進程緩衝區中的資料全部被寫入到通訊端發送緩衝區,這也就意味著write函數調用成功返回,並不能說明對端已經接受到了資料。
4.每個發送端TCP通訊端緩衝區需要保留資料副本直到被確認。
5.本端TCP以小於等於MSS大小的塊加上TCP首部構成TCP分節傳遞給IP。(這裡提到了一個最小重組緩衝區位元組數,查了一下,這代表IPv4和IPv6都必須保證支援的最小資料報大小其中IPv4是576位元組,IPv6是1500位元組)
6.最後,IP層給每個TCP分節安上一個IP首部,並且根據TCP分節中提供的對端IP地址尋找路由表項以確定外出介面,然後把資料報傳遞給相應額的資料鏈路。
UDP
當某個應用進程寫資料到一個UDP通訊端中時將經過下面步驟:
1.UDP通訊端沒有發送緩衝區,但是卻有一個SO_SNDBUF通訊端選項來修改發送緩衝區的大小(這表示應用進程寫入該通訊端的UDP資料報大小的上限。)
2.因為UDP是不可靠的,發送端不必儲存資料的副本。
3.UDP資料報首部是8個位元組,傳給IP層後,又安上相應的IP首部構成IP資料報,執行路由操作確定外出介面,或者直接把資料報加入資料連結層輸出隊列。
4.UDP沒有MSS因此比TCP更容易分區。
5.write返回成功表示縮寫資料報已經被加入資料連結層輸出隊列。
UNIX網路編程筆記(1)—傳輸層協議