你須要知道的TCP/IP

前言

TCP/IP 協議 是網絡通訊的基石,TCP/IP 協議 不是隻有 TCPIP 協議,它是整個網絡通訊中全部協議的簡稱。php

維基百科:TCP/IP協議簇)html

維基百科:OSI模型java

# TCP/IP 參考模型維基百科
https://zh.wikipedia.org/wiki/TCP/IP%E5%8D%8F%E8%AE%AE%E6%97%8F
# OIS 參考模型維基百科
https://zh.wikipedia.org/wiki/OSI%E6%A8%A1%E5%9E%8B

<img src="http://oss.mflyyou.cn/blog/20200801104517.png?author=zhangpanqin" alt="image-20200801104517510" style="zoom:50%;" />linux

圖片來自 《圖解 TCP/IP 與 OSI 參考模型》 中 TCP/IP 協議分層模型

OSI 參考模型 (七層)是個理論模型,實際咱們用的是 TCP/IP (四層)模型。不過咱們能夠經過 OSI 參考模型 來學習 TCP/IP 模型。面試

應用層:應用程序通訊細節的協議,好比經常使用的 HTTPredis

傳輸層:主要是負責兩個節點之間數據傳輸,通訊標識是 port 端口號。算法

網絡層:地址管理和路由選擇,在兩點之間找到一條最佳的通訊路線,通訊標識是 IP後端

數據鏈路層:負責物理層面連接的通訊(同一個網段內)。也就是局域網中經過交換機連接的節點。通訊標識是 Mac 地址,網卡出廠自帶的標識。centos

物理層:將鏈路層的數據幀(字節流)轉換爲電壓或光信號傳播。數組

網絡通訊能夠作什麼呢?

redisson (一個操做 redis 的 java 庫),就是使用的 netty 來作網絡通訊鏈接 redis 服務的。

微服務中的服務發現和通訊,就須要你熟悉網絡通訊。

你要是在通訊行業,那就不是瞭解了,你連協議的規範都得很清楚,否則路由器你都整不出來,還說什麼 5G

做爲一個 Java 後端開發,主要是開發偏應用層面的程序,離底層相對比較遠,熟練掌握便可,若是之後作通訊行業的時候,你也必定會進一步學習的相關細節的。

TCP/IP 你不瞭解,也不會有多大問題,CRUD 仍是沒有問題的。可是你瞭解了以後,平常開發定位和解決問題方面有很大助力,總之學習 TCP/IP 是一個重要不緊急的事情,根據本身目標和層次安排。

本文內容

  • 局域網中各節點怎麼通訊
  • 介紹 IP,ICMP,ARP 協議在網絡層的做用及路由表的做用,及網段劃分,子網掩碼、網關的做用
  • 介紹交換機和路由器的做用
  • 介紹 TCP/IP 三次握手和四次揮手,TCP 中通訊狀態的做用,滑動窗口
  • 介紹 tcp 包格式,ip 包格式,鏈路層 數據格式

交換機與路由器

交換機

維基百科:交換機)

交換機上有多個端口(不是 port)供計算機鏈接,交換機會維護端口與鏈接這個端口的 PC 的 Mac 地址映射表。當交換機接受到數據的時候,會根據目的 Mac 地址,發送到對應的端口上,而後通過網線發送到目的 PC。

交換機連接多個電腦組成一個局域網,交換機連接交換機又能夠組成一個更大的局域網。

好比 A、B 交換機各有 100 個端口,A 連接了 99 個PC,而後 B 交換機連接99 個,再將其中的一個端口 A/B 之間相互鏈接組成一個更大的局域網。

路由器

維基百科:路由器)

路由器工做在網絡層,主要用於將一個網段數據包轉發到另外一個網段內。路由器上也會有個幾個 LAN 口 (Local Area Network,局域網),用於創建局域網。還會有一個 WAN(Wide Area Network,廣域網),鏈接運營商的網絡。

路由器也具備交換機的功能,只是 LAN 口 比較少,能夠接入的電腦比較少。

PC 或者 手機 鏈接無線路由器時也會給 PC 分配一個局域網 IP,子網掩碼,網關等。

我住的地方的網絡拓撲圖以下:未命名文件

當手機與電腦通訊的時候,實際經過 LAN 口走局域網通訊。

當手機訪問 維基百科 時,實際是經過路由器跳入到光貓網段,再經過光貓跳入到小區運營商的網絡,… 到維基百科的服務器上。

只要須要有 IP 地址的設備(光貓,路由器,PC,手機)都須要有網卡,網卡出廠自帶有 Mac 地址。IP 和 Mac 地址的做用後文中會介紹。

image-20200801144243065

交互機和路由器的區別

<font color=red>這部份內容是我本身的理解,我沒有在網上找到資料佐證,請謹慎對待</font>

其實交換機和路由器硬件差異不大,只是硬件上的軟件決定了它能作什麼。

2 層交換機上的軟件(只有數據鏈路層)可能只作解析幀,拿到 mac 地址,而後查找當前交換機的端口對應的 mac 地址,而後從對應的端口傳遞過去。

路由器(有網絡層和數據鏈路層),當拿到數據包的時候,發現目的 mac 地址不是本身,就會將數據包經過 LAN 口發送出去。

當發送的數據包的 目的 MAC 地址 是當前路由器上 MAC地址 ,路由器就會對其解包,拿到數據包 目的 IP ,而後根據 目的 IP 匹配下一跳 mac 地址,封包爲新的幀數據發送出去。

TCP/IP 通訊

TCP_IP 同一以太網 (2)

從發送端發送數據的時候,數據通過每層的封包,經物理層傳送到接收端。接收端收到數據包,一層一層進行拆包,而後將數據數據發送給我接收端的應用層的應用程序。

一般咱們說的第一層就是 物理層 ,第二層是 鏈路層 …...

數據鏈路層

image-20200801220255714

源 MAC 地址 就是發送端的 MAC 地址,目標 MAC 地址不是最終的 MAC 地址,是下一跳節點的 MAC 地址。

類型 指的是這個以太網幀中的 數據 是何種類型的數據,好比 IPV4,IPV6。而後調用對應的接口進行處理。

數據鏈路層傳輸的幀是有大小限制的(64-1518 字節),能傳輸的數據的最大值就是 最大傳輸單元,簡稱 MTUMaximum Transmission Unit。這個值在以太網中一般是 1500。

# 查看網卡對應的 MTU
ifconfig -a
netstat -i

網絡層

網絡層主要以 IP 協議爲主,也有 ICMP,ARP(在 TCP\IP 模型 中,arp 屬於網絡層。在 osi 七層模型arp 數據鏈路層。)。

DNS

IP 是網絡層通訊的標識。可是 IP 不容易記憶,因此出現了 域名

訪問 DNS 能夠將域名解析爲 IP

能夠在本地配置 host ,定義域名和 IP 對應關係,這樣就不用解析了。

也能夠在電腦配置 DNS 解析時訪問的 ip,這樣域名解析時就會訪問這個服務。

<img src="http://oss.mflyyou.cn/blog/20200801182357.png?author=zhangpanqin" alt="image-20200801182357581" style="zoom:50%;" />

# 解析域名的 ip
dig www.mflyyou.cn

IP 基礎

IP 地址 又能夠分爲 IPV4IPV6,目前使用比較廣的是 IPV4 ,因此只介紹 IPV4

IP 地址 由 32 (2 進制)位組成,32 位被 . 分爲了四組。每組 8 位,十進制表示就是 xxx.xxx.xxx.xxx(xxx 取值在 0-255)。

IP 地址網絡地址 (網段) 和 主機號

同一個網段的電腦用 2 層交互機相連,而後就能夠局域網通訊了。

同一個網段內,主機號不能重複,重複主機號的電腦不能上網。

爲了便於區分出 IP 在那個網段,引入了子網掩碼 (netmask)。IP 地址與子網掩碼按位與計算能夠得出網段,32 位 中取出網段所在的位,剩餘就是主機號能取得值。

IP 中主機號全爲 0 就是網段,全爲 1 就是廣播地址。這兩個是不能被分配給電腦的。

IP:192.168.202.116

子網掩碼:255.255.252.0

網段爲:192.168.200.0

廣播地址爲:192.168.203.255

IP:192.168.201.56

子網掩碼:255.255.252.0

網段爲:192.168.200.0

廣播地址爲:192.168.203.255

ICMP

網絡層是不可靠傳輸,發送失敗的數據包,網絡層是不會再發一次數據包,可是會有 ICMP 包回覆告訴你發包究竟是什麼問題。傳輸層 能夠根據 ICMP 來判斷是否須要重發包。

ARP

ARP 用於 IP 的 對應的MAC 地址。

目的 IP 在路由表中查詢下一跳的 IP,在查詢這個 IP 對應的 mac 地址

查詢的這個 IP 是當前網段內的 ip,它會經過廣播地址發送給當前網段內全部主機,收到這個協議的主機會判斷是不是當前主機,是的話就會恢復當前 ip 對應的 MAC 地址。

image-20200801223925086

通訊過程分析

未命名文件

當我在瀏覽器輸入 wwww.mflyyou.cn 的時候:

一、先解析域名(DNS) www.mflyyou.cnIP (目的 IP: 47.104.168.20)

二、將目的 IP 與本地路由表中的子網掩碼進行按位與,計算出網段與 Destination 匹配,看哪一個匹配度更高,走哪一個條目。都沒有匹配到走默認條目(0.0.0.0)

# 查看路由表
route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.31.1    0.0.0.0         UG    100    0        0 eth0

三、而後用 arp 查詢(有緩存可不查,走緩存)192.168.31.1 對應的 mac 地址

四、數據鏈路層封裝以太網幀數據包中的目的 MAC 地址址就是 192.168.31.1 對應的 mac 地址,而後將數據幀發送到下一個節點(這也就常說的下一跳,數據包發送只是找到當前接節點的下一個節點)

五、到下一個路由器節點,路由器解包,看是發給本身的數據包(根據幀中的目的 MAC 地址與本身的 MAC 地址比較),不是就丟棄了;是的話就會解包拿到 目的 IP (47.104.168.20),而後在當前路由器上根據路由表查詢下一跳,發送給下一個節點;。。。。 直到目的服務器,或者發送的包 TTL 爲 0

六、發到目的服務器的網卡上,網卡將數據複製到內核緩衝區,應用程序從緩衝區中讀取數據

IP 數據格式

<font color=red>IPv4 數據結構</font>

<img src="http://oss.mflyyou.cn/blog/20200802000153.png?author=zhangpanqin" alt="image-20200802000153692" style="zoom:50%;" />

圖來自《圖解 TCP/IP》
  • 版本(Version):4 bit 構成,表明當前 IP包是哪一個版本,IPv4 或者 IPv6,爲 4 時表示當前是 IPv4。
  • 首部長度(Internet Header Length):由 4 bit 構成,通常 20字節大小。
  • 標識(Identification):用於分片重組用,值相同的屬於同一個 IP 數據包
  • 標誌(Flags):用於判斷是否還有分片。
  • 總長度(Total Length):16 個字節,IP 數據包總的長度,最長可爲 65525 字節。
  • 分段偏移(Fragment Offset):表示這個包在原來 IP 包中的位置。
  • 生存時間 TTL(Time To Live): IP 包在路由轉發中存活的時間,被路由轉發一次,次數減 1,爲 0 時,數據包被丟棄。
  • 掛載協議標識 (Protocol):記錄數據包中 Data(實際發送的數據)是什麼類型的數據,1 標識 ICMP, 4 標識 IP, 6標識 TCP, 17 標識 UDP。根據這個掛載協議程序就知道調用哪些接口來進行後續的處理了。

數據鏈路層中 以太網數據幀MTU 是 1500 字節,限定了 IP 數據包最大爲 1500 字節。而後去掉 IP 包首部 20 字節,通常 IP 數據包發送的數據爲 1480 字節。

當咱們發送一個 3058 字節的 IP 數據包時,這顯然大於了數據鏈路層的 MTU (1500 字節)。因此網絡層會對大於鏈路層MTU 的數據包進行分片。拆分一個一個的1500 的數據包發送接收端,接收端接收到這三個包,在匯聚成一個完成的,在調用傳輸層接口。

# 會發送 3050 字節數據與 8 字節的 ICMP 首部,這個命令會總共發送 ip 數據大小 3058 字節。
ping -s 3050 www.mflyyou.cn

image-20200801230015436

<img src="http://oss.mflyyou.cn/blog/20200801230141.png?author=zhangpanqin" alt="image-20200801230141070" style="zoom:50%;" />

<img src="http://oss.mflyyou.cn/blog/20200801230528.png?author=zhangpanqin" alt="image-20200801230528418" style="zoom:50%;" />

<img src="http://oss.mflyyou.cn/blog/20200801230423.png?author=zhangpanqin" alt="image-20200801230423653" style="zoom:50%;" />

經過 wireshark 抓包能夠看到,IP 數據包的首部長度佔了 20 字節,實際每次發送數據爲 1480 字節,最後一次發送了 98 字節。

從 Fragment 和 Identification 能夠看到這三個包屬於同一個 IP 數據包,而且從 Fragment offset 能將這三個包合成一個完成的網絡層數據包。

傳輸層 TCP

TCP 是面向連接的,可靠的,全雙工協議。

面向鏈接就是發送以前,須要創建一個連接通道,數據都是在這個連接中發送。

網絡層 是不可靠協議,數據發送失敗是不會重發的。

TCP 協議中發送端會記錄發送的那些數據包被客戶端收到了。接收端接受數據以後,會回覆一個 ACK 包(由數據格式中的控制位決定),確認應答號告訴發送端哪些數據包接收到了。

發送端 發送了數據包以後,這個包會有一個重發倒計時,在這個倒計時內沒有收到接收端 回覆 ACK 包,就會再重發一個數據包。若是是 HTTP 請求 ,就至關於一樣的數據請求了兩次。

咱們知道支付接口都要求冪等性,有一部分緣由是由於這個超時重發。發送端發送了請求,接收端處理好業務以後回覆的 ACK 包超時,發送端超時重發這個請求。若是不保證接口的冪等性,那麼扣錢就會扣兩次。

咱們要作的就是保證這個重發 n+1 次再也不扣用戶的錢,通常會用一個 token 來判斷是否是重複請求,重複就不走扣款處理了,直接返回已經支付,保證接口的冪等性。或者用一個帳單流水來保證冪等性。

鏈接既然須要創建,那麼也會有鏈接斷開。斷開鏈接需雙方協商好以後斷開鏈接,不能單方面關閉而無論對方。由於創建鏈接以後佔用的計算機資源須要釋放掉。你單方面強制斷開鏈接釋放了資源,可是對方不知道須要斷開鏈接,分配的計算機資源一直佔用那就是不可靠協議了。因此 TCP 有四次揮手斷開鏈接。

全雙工就是鏈接兩邊均可以主動發送接受數據,而不是輪訓訪問有沒有數據到達。

TCP 數據格式

首先咱們要先了解 TCP 數據格式,才能更容易知道 TCP 的工做原理。

<img src="http://oss.mflyyou.cn/blog/20200802000246.png?author=zhangpanqin" alt="image-20200802000246545" style="zoom:50%;" />

源端口號(Source Port)

佔用 2 個字節。標識 發送端 程序的端口號,當接收端須要回覆消息的時候,須要帶上這個端口號。

目的端口號(Destination Port)

佔用 2 個字節。標識 接收端 程序的端口號,能夠傳遞給監聽在這個端口的程序

控制位(Control Flag)

佔用 6 位,不滿一個字節。標識當前 TCP 包是什麼包,在通訊過程當中有一些特殊做用。

SYN

表示但願創建三次握手連接,並初始化序列號。

ACK

對收到數據包的應答確認。接收端接受數據以後,會回覆 ACK 包,發送端從其上 確認應答號 知道接收端哪些數據已經接受了。

FIN

表示沒有數據發送了,但願斷開鏈接

PASH

接收端接收到這個數據包須要馬上傳遞給應用層,不能等待接收更多的數據包

RET

連接出現異常,須要強制斷開鏈接

URG

表示包中有須要緊急處理的數據

序列號(Sequence Number)

佔用 4 個字節。TCP 三次握手的時候,發送端和接收端各自初始化(隨機的)本身的 `序列號。

咱們能夠這樣理解,發送端發送的數據就是一個字節數組,這個數組中每一個字節都有一個 序列號

發送端和接收端都有本身的序列號,而且不相同,在三次握手的時候本身初始化,而後告知對方。

確認應答號(Acknowledgement Number)

佔用 4 個字節。確認應答號 也是指的序列號,指的是指望發送端下次發送的序列號,這個序列號(確認應答號)以前的數據已經接受處理了。

下圖是我抓包創建三次連接,而後我發送三次 1\n 數據。

三次握手,發送端經過發送 SYN 包,發送本身的初始化序列號(893189542),而後發送的每一個字節都會有一個序列號。

接收端發送 ACK 包中的 確認應答號,指明這個序列號以前的數據我已經接受了。

<img src="http://oss.mflyyou.cn/blog/20200802205000.png?author=zhangpanqin" alt="image-20200802205000890" style="zoom:50%;" />

窗口大小(Window Size)

窗口大小適用於流控的。發送端不能一直髮送消息,須要根據個人接受能力來調整發包的速率。

未命名文件

內核會爲每一個 TCP/IP 分配讀寫緩衝區,網卡會從這些讀寫緩衝區中把數據取走,而後發送。數據大體能夠分爲這幾類。

TCP/IP 是可靠鏈接,因此它須要記錄哪些數據發送已被對方接受了(由確認應答號能夠知道),接受的數據會被淘汰掉,節省內存空間。

窗口大小做用:接收端會經過 ACK 告訴 發送端 調整窗口大小。

當窗口中的數據全都是 已發送未確認數據 時,發送端不能再發送新的數據,必須等待窗口空出位置來。

未命名文件 (2)

當有一個數據包被確認了,發送端就能夠發送新的數據包。已發送未確認數據 會在超時的時候從新發包。

滑動窗口百度百科)

校驗和 (Checksum)

佔用 2 個字節。校驗和 用於校驗數據包是否損壞。每一個數據包都一個 校驗和接收端 接收到數據以後,使用相同的算法對數據計算出一個值,而後和 校驗和比較,不同說明數據在傳輸過程當中損壞了,接收端 會丟棄這個包,等待 發送端 從新發這個包。

TCP 中 MSS

鏈路層能發送的最大以太網幀爲 1500 字節,MTU 爲 1500。

IP 數據包能發送的最大數據 = MTU - IP 首部大小(通常 20 字節),IP 數據包超過這個 1500 字節會分片

TCP 傳輸數據以段 (Segment) 爲單位。

TCP 爲了不分片,會主動將數據分片以後交給網絡層。 TCP 能傳輸的最大分段(只是數據不包括首部)稱之爲 Max Segment Size,簡稱爲 MSS。

MSS = MTU - IP 首部大小 - TCP 首部大小

在以太網中 TCP 的 MSS = 1500(MTU) - 20(通常 IP 首部大小) - 20(通常 TCP 首部大小)= 1460,這個值須要根據首部計算

image-20200802211639395

MSS 值在三次握手時,會經過 MTU 計算的。

TCP 三次握手創建鏈接

<img src="http://oss.mflyyou.cn/blog/20200802212532.png?author=zhangpanqin" alt="image-20200802212532628" style="zoom: 33%;" />

圖片來自 碼出高效:Java 開發手冊

爲何是三次握手創建鏈接呢?不少面試官也會問。這實際上是可靠鏈接的最少握手次數。

<img src="http://oss.mflyyou.cn/blog/20200802212808.png?author=zhangpanqin" alt="image-20200802212808724" style="zoom:50%;" />

圖片來自 碼出高效:Java 開發手冊

這裏還有個 全鏈接隊列和半連接隊列 的知識點

TCP 四次揮手斷開鏈接

<img src="http://oss.mflyyou.cn/blog/20200802213247.png?author=zhangpanqin" alt="image-20200802213247725" style="zoom: 33%;" />

圖片來自 碼出高效:Java 開發手冊

CLOSE_WAIT 是收到對方 FIN 包以後,回覆 ACK 以後進入的狀態。以後不會接受數據了,進行已收數據的業務處理以後,在發送一個 ACK+FIN,進入 LASK_ACK,而後等待對方發送 ACK,超時沒有等到,會重試發送(內核能夠配置重試發送次數)。當你發現服務端有大量的 CLOSE_WAIT 連接,服務端的代碼有問題,須要排查。

TIME_WAIT 的連接多的話,服務端能夠優化,否則這個連接會佔用很長時間,在高併發的時候,會致使沒有資源釋放的慢。

MSL 爲 Maximum Segment Lifetime,在 centos 中默認值爲 60s

# sysctl -a | grep tcp_fin_timeout
# 推薦小於 30,也不能過小,15-30
net.ipv4.tcp_fin_timeout = 60

說明 A 機器連接會在 120 s 以後才能釋放。這個是爲了保證 B 機器 能接收到最後一個 ACK,當處於 LAST_ACK 的超時沒有收到A 發來的 ACK 的話,會重試發送一個 FIN+ACK。這個 2MSL 也是爲了最大限度保證 B 機器正常關閉。

三次握手創建鏈接四次揮手斷開鏈接 須要結合抓包工具本身分析一下,理解會更深入。

網絡抓包

Wireshark 抓包分析是很厲害的,mac oslinux 都有命令行程序 tshark,能夠在服務器用 tshark 抓包,拿到本地來分析。

抓包的時候必定要指定抓什麼包,什麼包都抓的話,一會你的電腦內存就飆升好多(別問我爲啥知道,問就是 30g 內存都讓它吃了)。

Wireshark 有個 抓包過濾器顯示過濾器。抓包的時候指定抓什麼包這是 抓包過濾器的做用,抓包以後顯示顯示那些內容那是 顯示過濾器的做用

# -i 指定那個網卡 
# -f 指定抓包過濾器
# -Y 顯示過濾器
# -w 指定抓包數據到文件,沒有 -w 輸出屏幕
# -V 顯示 TCP/IP 每層包的詳細信息,建議將抓包的文件在圖形化界面中查看,不指定 -V
tshark  -i en0 -f "tcp" -Y "http"

# 抓取訪問 www.mflyyou.cn 的包
tshark  -i en0 -w a.pcap -f "host www.mflyyou.cn"

# 指定抓那個協議 tcp,ip,icmp,arp,udp
tshark  -i en0 -f "tcp"


# host 指定域名或者 ip
# port 指定端口
# 訪問 www.mflyyou.cn 的包,或者 icmp. ping www.baidu.com 也會被抓到
tshark  -i en0 -f "host www.mflyyou.cn || icmp"
tshark  -i en0 -f "port 80"

# 條件之間支持邏輯運算符 || && !
# 抓取 ssh 連接的包
tshark  -i en0 -f "host www.mflyyou.cn && port 22"

參考資料

《圖解 TCP/IP》

linux-tcp 說明

鳥哥私房菜:基礎網絡的概念


本文由 張攀欽的博客 http://www.mflyyou.cn/ 創做。 可自由轉載、引用,但需署名做者且註明文章出處。

如轉載至微信公衆號,請在文末添加做者公衆號二維碼。微信公衆號名稱:Mflyyou

相關文章
相關標籤/搜索