助記提要
- 協議棧的結構
- 協議棧創建連接的實際過程
- 協議棧發送數據包的2個判斷依據
- TCP確認數據收到的原理
- 斷開連接的過程
- 路由表和ARP
- MAC地址的分配
- MAC模塊的工作
- 通過電信號讀取數據的原理
- 網卡和協議棧接收包的過程
- ICMP
- UDP協議的適用場景
2章 用電信號傳輸TCP/IP數據 探索協議棧和網卡
1. TCP部分
1.1 協議棧
底層實際負責收發消息的是協議棧、網卡驅動和網卡。協議棧是操作系統中的網絡控制軟件,
操作系統的協議棧分為上下兩部分。上部分為兩塊,分別是用TCP協議收發數據的部分和用UDP協議收發數據的部分。一般應用程序都使用TCP收發數據,像DNS查詢等收發較短的控制數據時用UDP。
下部分是IP協議部分,負責將切分的網絡包發送給通信對象。這一層還有ICMP和ARP協議。ICMP用于報告網絡包傳輸過程中的錯誤和控制信息,ARP用于根據IP地址查詢MAC地址。
協議棧下面是網卡驅動程序,負責控制網卡硬件。再下是網卡,負責實際的收發操作。
協議棧內有一塊用于存放控制信息的內存空間,記錄了通信對象的IP地址、端口號、通信狀態等信息。這些控制信息就是套接字的實體。
創建套接字時,先分配一個內存空間,然后在其中寫入初始狀態。
1.2 TCP頭部格式
字段 | 長度(位) | 含義 |
---|---|---|
發送方端口號 | 16 | 發送網絡包的程序的端口號 |
接收方端口號 | 16 | 接收方程序的端口號 |
序號 | 32 | 發送方告訴接收方,當前網絡包是所有發送數據的第幾個字節 |
ACK號 | 32 | 接收方告訴發送方已收到了所有數據的第幾個字節 |
數據偏移量 | 4 | 數據部分的起始位置,相當于頭部的長度 |
保留 | 6 | 保留字段,未使用 |
控制位 | 6 | 6個比特位表示不同的通信控制含義: URG:表示緊急指針字段有效; ACK:表示接收數據序號字段有效,數據已被接收到; PSH:表示通過flush操作發送的數據; RST:強制斷開連接,用于異常中斷情況; SYN:發送方和接收方相互確認序號,表示連接操作; FIN:表示斷開連接 |
窗口 | 16 | 接收方告知發送方窗口大小。即無需等待確認可一起發送的數據量 |
校驗和 | 16 | 用于檢驗是否出現錯誤 |
緊急指針 | 16 | 表示需要緊急處理的數據位置 |
可選字段 | 可變 | 額外添加的可選字段 |
通信操作使用的控制信息,一是數據包頭部記錄的信息,二是套接字中記錄的信息。
1.3 連接操作實際過程
連接操作表示通信雙方交換控制信息,在套接字中記錄這些必要信息并準備數據收發的一系列操作。(三次握手)
1-1 應用程序調用socket庫的connect組件,服務器的IP和端口號被傳遞給協議棧的TCP模塊;
1-2 TCP模塊創建包含控制信息的頭部。其中SYN位設為1,表示連接;
1-3 TCP模塊把信息交給IP模塊,IP模塊進行網絡包發送;
1-4 服務器的IP模塊收到的數據傳遞給TCP模塊;
1-5 服務器的TCP模塊根據頭部的端口號找到對應的套接字,在這個套接字寫入相應信息,將狀態改為正在連接;
2-1 服務器的TCP模塊創建響應,響應的TCP頭部的ACK控制位為1,表示成功接收到客戶端發來的網絡包。
2-2 服務器TCP模塊把TCP頭部交給IP模塊,由IP模塊向客戶端返回響應;
2-3 客戶端收到后,TCP模塊通過頭部信息確認連接操作是否成功。SYN為1表示連接成功,就向套接字寫入服務器的IP地址、端口號等信息,同時連接狀態改為連接完畢。
3 客戶端將ACK位設為1后,發回服務器,告訴服務器剛才的響應已收到。
1.4 協議棧發送數據的兩種依據
協議棧收到數據后不是馬上發送出去,而是先將數據存在發送緩沖區中。
應用程序交給協議棧發送的數據的長度是應用程序決定的,有的應用程序會一次性傳遞所有數據,有的會逐字節或逐行傳遞數據。如果一收到數據就馬上發送,就可能會發送大量小包,導致網絡效率下降,因此需要積累到一定量再發送。
MTU,表示網絡包的最大長度,以太網中一般為1500字節。
MSS,表示除去頭部后,網絡包能容納的TCP數據的最大長度。
- 協議棧會在從應用程序收到的數據長度超過或接近MSS時再發送出去,避免發送太多小包;
- 協議棧內部有計時器,當應用程序發送頻率低時,為避免等待過長時間造成延遲,經過一定時間后就會把網絡包發送出去。
長度和時間這兩個判斷依據是相互沖突的。協議棧會由于操作系統差異有不同的表現。應用程序可以在發送數據時指定選項,控制協議棧的發送操作。
應用層的大數據包到達發送緩沖區后,會被以MSS長度為單位進行拆分,拆分的每塊數據會被放入單獨的網絡包中。發送時,在每一塊數據前面加上TCP頭部,然后交給IP模塊執行發送操作。
1.5 TCP確認網絡包收到的原理
- TCP模塊拆分數據時,會計算出每一塊數據相當于從頭開始的第幾個字節,這個字節數會寫在TCP頭部的序號字段。
- 接收方收到網絡包時,通過序號知道這次的數據是從第幾個字節開始的。并使用網絡包的長度減去頭部長度算出數據長度。
- 接收方根據序號和數據長度判斷有無遺漏。
- 如果沒有遺漏,就把目前收到的數據長度寫到ACK號中返回給發送方。
- 發送方通過ACK號得知對方收到了多少數據。
為了避免發送過程被攻擊者預測到,實際發送時的序號初始值是隨機的。建立連接時,將SYN置為1的同時,也會將序號改為初始的隨機值,用來告知服務器。
TCP在得到對方確認收到數據的消息前,發送過的數據都會保存在發送緩沖區中。如果對方沒有返回某些包對應的ACK號,就重新發送這些包。
TCP的確認機制很強大,因此應用程序、網卡、集線器、路由器等都沒有錯誤補償機制,檢測到錯誤就直接丟棄。
1.6 ACK號
-
ACK號的等待時間
ACK號的返回快慢受很多因素影響,如網絡距離的遠近、網絡的擁塞程度等。
因此ACK號的等待時間不能設為固定的值。
TCP會在發送數據的過程中持續監測ACK號的返回時間,如果返回變慢,就延長等待時間,如果ACK號馬上返回,就縮短等待時間。 -
使用窗口管理ACK號
發送數據包后,等待ACK號的時間如果什么也不做,會很浪費。因此在等待ACK號的期間繼續發送后續的包,這樣的方式叫滑動窗口。這種方式減少了等待ACK號的時間浪費。接收方的TCP收到包后,會把數據存到接收緩沖區,然后組裝數據、計算ACK號、傳遞給應用程序。在操作期間,下一個包到了,會被暫存到接收緩沖區。如果數據到達的速率超過處理速率,緩沖區的數據會越來越多直到溢出。緩沖區溢出后就收不到后續的包了。
為了避免這種情況,接收方需要通過窗口字段告訴發送方自己能接收多少數據量,發送方按照這個值控制發送操作。
接收方能接收的最大數據量稱為窗口大小,經常用于TCP調優。接收方接收完數據后就需要返回ACK號,在數據傳遞給應用程序后就需要更新窗口大小。如果每收到一個包就向發送方分別發送ACK號和窗口更新,會使網絡效率下降。
因此接收方在發送ACK號和窗口更新時,不會馬上把包發送出去,而是等待一段時間,將兩種通知合并在一個包里發送。連續的ACK號和連續的窗口更新也能進行合并。 -
接收HTTP響應消息
請求消息發送完后,應用程序會調用read程序獲取響應消息。協議棧會取出暫存到接收緩沖區的數據傳遞給應用程序。如果這時請求剛發出去,接收緩沖區沒有數據,協議棧會將應用程序的委托掛起,等待響應消息到達后再繼續操作。
1.7 斷開連接過程
數據發送完畢后,斷開連接的過程(四次揮手):
- 服務器端的應用程序調用socket庫的close程序;
- 服務器的協議棧生成包含斷開信息的TCP頭部,其中的FIN位設為1;
- 協議棧委托IP模塊把數據發送個客戶端;
- 客戶端收到服務器發來的FIN為1的TCP頭部后,把自身的套接字標記為斷開操作狀態;
- 客戶端協議棧向服務器返回一個ACK號,告知服務器已收到斷開信息;
- 客戶端應用程序得知服務器的數據已經全部收完后,調用close程序結束數據收發操作;
- 之后,客戶端的協議棧生成一個FIN為1的TCP包發給服務器;
- 服務器收到后返回ACK信號,結束通信。
- 客戶端等待一段時間后,刪除套接字。等待是為了避免誤操作。
HTTP1.0中服務器發送完響應后就發起斷開過程;HTTP1.1后服務器不主動斷開,而是客戶端在沒有新請求時發起斷開。
2. IP部分
2.1 IP頭部
IP模塊的工作就是在包前面加上IP頭和MAC頭。IP頭包含IP協議規定的、根據IP地址將包發往目的地需要的控制信息。MAC頭部包含通過以太網的局域網把包傳輸到最近的路由器的控制信息。
字段 | 長度 | 含義 |
---|---|---|
版本號 | 4 | IP協議的版本號 |
頭部長度 | 4 | IP頭部的長度。會因可選字段而變化 |
服務類型 | 8 | 表示包傳輸的優先級 |
總長度 | 16 | IP消息的總長度 |
ID號 | 16 | 用于識別包的編號,一般為包的序列號。如果包被IP分片,則所有分片有相同的ID |
標志 | 3 | 僅兩位有效,一位表示是否允許分片,另一位表示是否為分片包 |
分片偏移量 | 13 | 當前包的內容為整個IP消息的第幾個字節開始的內容 |
生存時間 | 8 | 包的生存時間。為了避免網絡出現會環,導致一個包永遠在網絡中轉發。沒經過一個路由器,這個值會減1,減到0時這個包會被丟棄 |
協議號 | 8 | 表示協議的類型。十六進制表示:TCP為06,UDP為17,ICMP位01 |
頭部校驗和 | 16 | 用于檢查錯誤。現已不再使用 |
發送方IP地址 | 32 | 發送方的IP地址 |
接收方IP地址 | 32 | 接收方的IP地址 |
可選字段 | 可變長度 | 可選的其他控制信息。一般很少用到 |
- IP模塊如何使用路由表
路由表的每行包括目標子網地址(Network Destination)、轉發路由器的IP地址(Gateway)、發送包的網絡接口(Interface)、使用該行路由的傳輸成本(Metric)。
TCP模塊告知目標IP地址后,IP模塊在路由表中找這個地址所在的網絡,找到后把包由Interface記錄的網卡發送給Gateway記錄的路由器。路由表第一行是默認網關,無法匹配時會使用這一行。
發送方的計算機上可能會有多塊網卡,因此IP地址填寫的是發送使用的網卡的IP地址。
2.2 MAC頭部
以太網判斷網絡包目的地的方式和TCP/IP不同,因此需要采用相匹配的方式才能在以太網將包發到目的地。
字段 | 長度 | 含義 |
---|---|---|
接收方MAC地址 | 48 | 網絡包接收方的MAC地址 |
發送方MAC地址 | 48 | 網絡包發送方的MAC地址 |
以太類型 | 16 | 使用的協議類型。0800:,IP協議;0806,ARP協議;86DD,IPv6協議;0000-05DC,IEEE 8-2.3。TCP/IP中只用到0800和0806兩種 |
2.3 接收方MAC地址的獲取
路由表中能找到把網絡包發給誰(Gateway),但是只知道對方的IP地址,不知道MAC地址。
- ARP(Address Resolution Protocol)
地址解析協議。ARP會對同一子網中的所有設備廣播,詢問某個IP地址和哪個MAC地址對應。
內存中有一塊ARP緩存,其中保存了之前的查詢結果。在發送ARP包前先查詢緩存,避免網絡中增加過多的ARP包。ARP緩存有效期一般為幾分鐘。
MAC頭部是以太網需要的信息,卻由IP模塊裝配。這樣網卡只做單純的發送和接收,一塊網卡也能支持各種類型的包。
3. 網卡部分
3.1 以太網模型的發展
- 初始原型
通過收發器把不同網線的信號連接起來。一臺計算機發信號時,信號會流過整個網絡,到達所有設備。和MAC頭部的接收者地址匹配的設備接收信號包,其他設備丟棄這些包。 - 使用中繼式集線器
主干網線替換為了中繼式集線器,收發器網線替換為雙絞線。信號仍然會到達所有設備。 - 使用交換式集線器
信號只會到達MAC地址指定的設備。
以太網的三個性質:將包發送到MAC頭部接收方MAC地址表示的目的地,用發送方MAC地址識別發送方,用以太類型識別包的內容。
3.2 MAC模塊的MAC地址
啟動操作系統時,網卡驅動會對硬件進行初始化操作,包括硬件錯誤檢查、初始設置等。
初始化時,有一項是為MAC模塊設置MAC地址。網卡的ROM中保存著全世界唯一的MAC地址,是在生產網卡時寫入的,讀出后就能對MAC模塊進行設置。也能通過命令行或配置文件讀取MAC地址并分配給MAC模塊,這時會忽略ROM中的MAC地址。
3.3 MAC模塊的工作
收到IP模塊的包后,MAC模塊會把包從緩沖區取出,并在開頭加上報頭和起始幀分界符,在末尾加上用于檢測錯誤的幀校驗序列FCS。
- 報頭用來測量時鐘信號,長度56比特。
- 起始幀分界符用于標記包的起始位置,長度8比特。
- 末尾的幀校驗序列用于檢測傳輸過程中因噪聲導致的波形紊亂、數據錯誤,長度32比特。數據發生變化時,接收方計算出的FCS和發送方的就會不一致。
3.4 如何使用電信號讀取數據
0和1兩種比特可以使用特定的電壓和電流表示,但是當信號為連續的1或0時,比特之間的界限會消失,讀取時無法判斷。
解決這個問題的方式是加一組用于區分比特間隔的時鐘信號。兩組信號需要疊加在一起發送(避免傳輸太遠導致偏移)。
時鐘信號一般是固定的頻率變化的,只要對信號觀察一段時間,就能知道變化的周期。
3.5 半雙工模式的問題
發送信號的操作一種是集線器的半雙工模式,另一種是交換機的全雙工模式。
MAC模塊會把處理完的網絡包轉換為通用的電信號交給網卡的PHY(MAU)模塊,PHY把信號轉換為可在網線中傳輸的格式,然后通過網線發出去。
信號碰撞,在使用集線器的半雙工模式中,發送信號的過程中,接受線路也有信號進來時,兩組信號就會發生疊加,無法彼此區分。
此時會終止發送操作,并發送一段時間的阻塞信號讓其他設備也停止發送。等待一段時間后重試發送。等待時間是按照MAC地址生成一個隨機數計算出來的,重試時又發生碰撞會將等待時間延長一倍。重試10次后不行就報錯。
3.6 接收返回包的過程
3.6.1 網卡接受包的過程
PHY(MAU)把收到的信號轉為通用格式發給MAC模塊,MAC模塊把信號轉為數字信息,放到緩沖區中。
在到達FCS時,會把報頭到結尾的比特套用公式計算出FCS和包尾的FCS作比較,錯誤包會被丟棄。FCS校驗正確后,如果MAC頭部中接收方的MAC地址和網卡初始化時分配的MAC地址一致,MAC模塊就把包放到緩沖區中。
網卡通過中斷機制通知計算機收到一個包。
網卡先向擴展總線中的中斷信號線發送信號,該信號線通過計算機的中斷控制器連接到CPU。CPU收到中斷信號時,會掛起當前任務,轉到中斷處理程序。中斷處理程序調用網卡驅動。網卡驅動從緩沖區中取出收到的包,通過MAC頭部的以太類型判斷協議類型,然后將數據交給對應的協議棧。
中斷是有編號的。網卡安裝時在硬件中設置中斷號,中斷處理程序會把中斷號和相應的驅動綁定。
3.6.2 協議棧接收數據
TCP/IP協議棧收到網卡發來的數據,IP模塊會檢查IP頭的格式,確定接收方的IP地址與網卡的地址一致。
如果接收到的包是經過分片的,IP模塊會先暫存在內存中,等全部的相同ID的包到達后還原為原始的包。
之后數據包交給TCP模塊。TCP模塊根據IP頭部的接收方和發送方IP地址,以及TCP頭部的接收方和發送方端口號找到對應的套接字,執行后續的操作。
查找套接字同時需要接收方和發送方的IP地址和端口號,所以TCP模塊需要查詢IP頭部的信息。TCP和IP模塊被看成一個整體,沒有嚴格劃分。
3.6.3 ICMP
ICMP協議用于傳輸出錯時報告錯誤信息。屬于網絡層協議,主要在主機和路由器之間傳遞控制信息。IP數據無法訪問目標、IP路由器無法按當前速率轉發數據包時會自動發ICMP消息。
- ICMP規定的各種消息類型
| 消息 | 類型 | 含義 |
| — | — | — |
| Echo reply | 0 | 響應Echo消息 |
| Destination unreachable | 3 | 出于某些原因包沒有到達目的地而是被拋棄,通過此消息通知發送方。可能原因包括IP地址在路由表中不存在;目標端口不存在對應套接字;需要分片,但分片被禁用 |
| Source quench | 4 | 發送的包數超過路由器的轉發能力時,超過的包會被丟棄,這時會通知發送方。路由器的性能不夠時,可能不會發送該消息,而是直接丟棄多余的包。 |
| Redirect | 5 | 查路由表發現包的入口和出口為同一個網絡接口時,表示該包不需要這個路由器轉發,發送方可以直接發給下一個路由器。此時路由器會發送這條消息,告知發送方下一個路由器的地址。 |
| Echo | 8 | ping命令發送的消息,收到這條消息的設備需要返回Echo reply消息,以確認通信對象是否存在。 |
| Time exceeded | 11 | 超過了IP頭部中的TTL字段表示的存活時間,被路由器拋棄。 |
| Parameter problem | 12 | 由于IP頭部字段存在錯誤而被丟棄。 |
4 UDP協議
4.1 UDP頭部
名稱 | 長度 | 含義 |
---|---|---|
發送方端口號 | 16 | 發送方的端口號 |
接收方端口號 | 16 | 接收方的端口號 |
數據長度 | 16 | UDP頭部后面數據的長度 |
校驗和 | 16 | 用于校驗錯誤 |
4.2 UDP適用場景
-
不需要重發的數據
在數據長,分包多的情況下,發生漏包時,為了高效傳輸,TCP只重發出錯或者未送達的包。 -
控制用的短數據
控制數據一般很短,一個包的大小就能容納。
這時使用UDP,不需要建立和斷開連接的開銷。出錯時,協議棧也不會知道。應用程序在沒有收到對方的回復時會選擇重發數據。 -
音頻和視頻數據
音頻和視頻數據有規定的送達時間,送晚了就會錯過播放時機。
重發需要消耗時間,也很可能錯過播放時機。
某些包缺少了只會產生一些失真和卡頓,是可接受的。