當前位置:
首頁 >
【网络通信与信息安全】之深入解析两台主机之间的通信过程和原理
發布時間:2024/5/28
26
豆豆
生活随笔
收集整理的這篇文章主要介紹了
【网络通信与信息安全】之深入解析两台主机之间的通信过程和原理
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、前言
- 本文通過在 Docker 容器中執行命令,來深入了解兩臺主機之間的通信過程。閱讀完本文,您將熟悉以下內容:
-
- Docker 的基本操作;
-
- 創建 socket 并發送 HTTP 請求;
-
- 路由表、路由決策過程;
-
- ARP 協議、ARP 表更新過程;
- 本文也是【網絡通信與信息安全】之深入解析從輸入一個URL到頁面加載完成的過程 的另一個角度的回答,將解決以下兩個問題:
-
- 不同局域網的兩臺主機之間的通信過程;
-
- 同局域網內的兩臺主機之間的通信過程。
二、準備 Docker 環境
① 下載鏡像
- 關于 Docker 的基礎概念 (容器、鏡像等),可以參考:Docker 入門教程。
- 在啟動 Docker 容器之前,需要先下載一個 Docker 鏡像,這里使用 Ubuntu 系統鏡像:
② 首次啟動
- 從鏡像初始化并進入容器:
- 參數說明:
-
- -i:讓容器的標準輸入保持打開,從而能夠接受主機輸入的命令;
-
- -t:為容器分配一個偽終端并綁定到容器的標準輸入上,-i 和 -t 結合,可以在終端中和容器進行交互;
-
- –name:為容器起一個名字,方便后續操作該容器,否則每次都需要查找容器的 ContainerID。
- 需要注意的是,每次 run 都會重新創建一個新的容器。
③ 配置環境
- 在容器內執行以下命令,安裝必要的工具:
- 安裝完成后,exit 退出容器。
④ 提交鏡像
- 如果不小心刪除了容器,容器內的所有更改也將丟失,因此使用 commit 命令來保存容器中的更改:
- 列出所有的鏡像,查看是否提交成功:
- 如果有多余的無用鏡像,可以刪除:
⑤ 刪除容器
# docker rm <container> docker rm ubuntu- 查看當前所有容器,確認是否刪除成功:
- 之后,重新啟動容器:
- 到這里為止,就完成所有的環境安裝過程。
⑥ 退出容器
- 如果需要退出容器,可以在容器內執行:
⑦ 再次啟動容器
- 如果容器未啟動 (Exited),執行 start 命令:
- 如果容器已啟動 (Up),執行 exec 命令:
- 容器是否啟動,可以通過 docker container ls --all 查看。
三、應用層
- 當通過諸如 http.Get(“http://www.baidu.com/”) 這樣的 API 向服務器發送請求時,其底層實現無非以下幾個過程:
-
- 通過 DNS 協議將域名解析為 IP 地址;
-
- 通過操作系統提供的系統調用創建一個 socket 連接,這實際上是完成了 TCP 的三次握手過程;
-
- 通過 socket 連接以文本形式向服務端發送請求,在代碼層面實際上是在向一個 socket 文件描述符寫入數據,寫入的數據就是一個 HTTP 請求。
- 可以直接在終端實現這個過程,只需要以下三行命令:
① 建立連接
- 首先進入容器,查看當前系統中的文件描述符:
- 系統當前只有 /bin/bash 這一個進程,上面列出了該進程的 0、1、2、255 四個文件描述符:
-
- 文件描述符(file descriptor)是一個非負整數,從 0 開始,進程使用文件描述符來標識一個打開的文件;
-
- 系統為每一個進程維護了一個文件描述符表,表示該進程打開文件的記錄表,而文件描述符實際上就是這張表的索引;當進程打開(open)或者新建(create)文件時,內核會在該進程的文件列表中新增一個表項,同時返回一個文件描述符,也就是新增表項的下標;
-
- 一般來說,每個進程最多可以打開 64 個文件,fd ∈ 0~63;在不同系統上,最多允許打開的文件個數不同,Linux 2.4.22 強制規定最多不能超過 1,048,576;
-
- 每個進程默認都有 3 個文件描述符:0 (stdin)、1 (stdout)、2 (stderr)。
- 執行以下命令,建立一個連接:
- 該命令創建了一個指向 tcp://www.baidu.com:80 的可讀寫的 socket,綁定到當前進程的 3 號文件描述符:
-
- exec {fd}< file:以只讀的方式打開文件,并綁定到當前進程的 fd 號描述符;相應的,{fd}> 是以只寫的方式打開文件;
-
- 打開 /dev/tcp/host/host/host/port 文件實際上是建立連接并返回一個 socket,Linux 中一切皆文件,所以可以對這個 socket 讀寫。
- 執行以下命令,可以看到已經和 www.baidu.com 成功建立了 socket 連接:
② 發送請求
- 向 www.baidu.com 發送一個 GET 請求,只需要向 3 號文件描述符寫入請求報文 (格式):
- 說明:> 3:重定向到名為 3 的文件;>& 3:重定向到 3 號文件描述符。
③ 讀取響應
- 讀取 www.baidu.com 返回的響應:
④ 關閉連接
# 關閉輸入連接:exec {fd}<&-;關閉輸出連接:exec {fd}>& - exec 3<&- && exec 3>&-- 這樣就在 bash 中實現了 http.Get(“http://www.baidu.com/”)。
四、傳輸層
- 客戶端使用 socket(), connect() 等系統調用來和遠程主機進行通信。在底層,socket() 負責分配資源,connect() 實現了 TCP 的三次握手過程。
- Socket 通過 <源 IP、源 Port、目的 IP、目的 Port> 的四元組來區分 (實際上還有協議,TCP 或 UDP),只要有一處不同,就是不同的 socket。因此,盡管 TCP 支持的端口號最多為 65535 個,但是每臺機器理論上可以建立無數個 socket 連接。比如 HTTP 服務器只消耗一個 80 端口號,但可以和不同 IP:Port 的客戶端建立連接,實際受限于操作系統的內存大小。
- 使用 netstat 命令可以查看當前系統中的所有 socket:
- netstat 命令 State 一列的取值:
- 三次握手階段:
-
- 客戶端:
| SYN_SENT | 發送了連接請求,等待遠端的確認(三次握手第 1 步的結果) |
| ESTABLISHED | socket 已經建立了連接 |
-
- 服務端:
| LISTEN | 監聽來自遠程應用的 TCP 連接請求 |
| SYN_RECEIVED | 收到了連接請求并發送了確認報文,等待最終的確認(三次握手第 2 步的結果) |
| ESTABLISHED | socket 已經建立了連接,這是數據傳輸階段的狀態 |
- 四次揮手階段:
-
- 客戶端:
| FIN_WAIT1 | 發送了連接終止請求,等待確認,通常持續時間較短 |
| FIN_WAIT2 | 發送了連接終止請求并收到了遠程的確認,等待遠程 TCP 的連接終止請求,這個狀態表明遠程在收到此 socket 的連接終止請求后,沒有立刻關閉它的 socket |
| CLOSING | 發送了連接終止請求后,收到了遠程的連接終止請求,正在等待遠程對連接終止請求的確認,這個狀態表明雙方同時進入關閉狀態 |
| TIME_WAIT | 等待足夠的時間,以確保遠程 TCP 收到其連接終止請求的確認 |
| CLOSED | socket 已經沒有連接狀態 |
-
- 服務端:
| CLOSE_WAIT | 收到了遠程的連接終止請求,正在等待本地的應用程序發出連接終止請求 |
| LAST_ACK | 等待先前發送的連接終止請求的確認,只有在發送連接終止請求前先收到了遠程的連接終止請求時,才會進入此狀態 |
| CLOSED | socket 已經沒有連接狀態 |
五、網絡層
- 網絡層的功能是路由與尋址,數據包在網絡層是一跳一跳地傳輸的,從源節點到下一個節點,直到目的節點,形成一個鏈表式的結構。
- 當數據包到達網絡中的一個節點時,該節點會檢查數據包的目的 IP 地址,如果不是自己的 IP 地址,就根據路由表決定將數據包發送給哪個網關。
① 路由表
- 電腦、手機、路由集等都可以視為網絡層的一個節點 (或一臺主機),每個節點都有一個路由表。網絡層的節點通過路由表來選擇下一跳地址 (next hop address)。
- Ubuntu 系統可以通過以下命令查看路由表:
- 路由表由一組規則組成,每條規則包含以下字段:
-
- Destination:目的地址,可以是主機地址或網絡地址,常見的是網絡地址;
-
- Gateway:網關地址;
-
- Genmask:目的地址的子網掩碼;
-
- Iface:網卡名;
-
- Others…
- 當 Destination 為 0.0.0.0 時,其 Gateway 為當前局域網的路由器 / 網關的 IP 地址。當 Gateway 為 0.0.0.0 時,表示目的機器和當前主機位于同一個局域網內,它們互相連接,任何數據包都不需要路由,可以直接通過 MAC 地址發送到目的機器上。
- 通過 Destination 和 Genmask 可以計算出目的地址集。例如對于下面的表項,其含義為“所有目的 IP 地址在 192.168.1.0 ~ 192.168.1.255 范圍內的數據包,都應該發給 0.0.0.0 網關“。
- 當 Genmask 為 255.255.255.255 時,代表這條規則的 Destination 不再是一個網絡地址,而是一個網絡中的一臺特定主機,這樣的規則可能對應一條點對點信道 (Point to Point Tunnel)。
- 路由表中的規則可以手動指定,也可以通過路由協議來交換周圍網絡的拓撲信息、動態更新。
② 路由決策過程
- 當一個節點收到一個數據包時,會根據路由表來找到下一跳的地址。具體而言,系統會遍歷路由表的每個表項,然后將目的 IP 和子網掩碼 Genmask 作二進制與運算,得到網絡地址,再判斷這個地址和表項的 Destination 是否匹配:
-
- 如果只有一個匹配項,直接將數據包發送給該表項的網關 Gateway;
-
- 如果有多個匹配項,則選擇子網掩碼最長的那個規則,然后發送給對應的網關;
-
- 如果沒有匹配項,則將數據包發送給默認網關;
- 上面最后一種情況實際上不會出現,因為路由表中包含了下面這條規則:
- 任何目的 IP 和全 0 的 Genmask 作與運算,一定會得到全 0 的 Destination,這保證所有未知的目的 IP 都會發送給當前局域網的默認網關 (比如路由器),由后者決定下一跳的地址。
③ 案例分析
- ping www.baidu.com 的路由決策過程;
- ping 局域網的另一臺主機 的路由決策過程;
- 對于以下的路由表,路由器會如何轉發目標 IP 為 128.75.43.16 和 192.12.17.10 的數據包?
- 結果分析:
-
- 目標 IP 位于外部網絡,默認會發給本局域網的路由器,路由器連接外部網絡,知道該如何轉發數據包,例如交給更高一級的運營商網關;
-
- 同局域網的主機交換數據不需要網關或路由器,直接發給交換機,交換機根據 Mac 地址發送到對應的主機;
-
- A and D,128.75.43.16 匹配了前兩條規則,相應的 Destination 均為 128.75.43.0,數據包會發送給具有最長子網掩碼的網關,192.12.17.10 沒有匹配任何 Destination,數據包發送給默認網關。
六、數據鏈路層
① ARP 協議
- 當網絡層選擇一個特定 IP 的主機作為下一跳時,如何將數據包正確的發送給該主機?這里需要在數據包外面加上下一跳的硬件地址 (MAC),在數據包的整個傳輸過程中,目的 MAC 地址每一跳都在變,但目的 IP 地址不變。
- 如何根據 IP 地址找到相對應的 MAC 地址?這需要使用 ARP 協議 (Address Resolution Protocol,地址解析協議)。每臺主機都設有一個 ARP 高速緩存表,記錄本局域網內各主機的 IP 地址到 MAC 地址的映射。
- 執行以下命令可以查看主機的 ARP 緩存表:
- ARP 高速緩存是自動更新的,當主機 A 向本局域網的主機 B 發送數據包時,如果 ARP 高速緩存中沒有主機 B 的硬件地址,就會自動運行 ARP 協議,找出 B 的硬件地址,并更新高速緩存,過程如下:
-
- 主機 A 在局域網內廣播一個 ARP 請求分組,內容為:“我的 IP 是 IP_A,硬件地址是 MAC_A,我想知道 IP 地址為 IP_B 的主機的硬件地址“;
-
- 主機 B 接受到此請求分組后,如果要查詢的 IP 地址和自己的 IP 地址一致,就將主機 A 的 IP 地址和 MAC 地址的對應關系記錄到自己的 ARP 緩存表中,同時會發送一個 ARP 應答 (單播),內容為:“我的 IP 地址是 IP_B,硬件地址是 MAC_B”;
-
- 其他主機的 IP 地址和要查詢的 IP 地址不一致,因此都丟棄此請求分組;
-
- 主機 A 收到 B 的 ARP 響應分組后,同樣將主機 B 的 IP 地址和 MAC 地址的對應關系記錄到自己的 ARP 緩存表中。
- ARP 協議只用于局域網中,不同局域網之間通過 IP 協議進行通信。
② ARP 協議抓包
- 首先,需要另一個終端來監聽容器內的網絡請求,假設已經通過 docker start 啟動了一個容器,使用 docker exec 命令來創建一個新的終端會話:
- 為了便于表示,將一開始 docker start 創建的容器終端記為 A,docker exec 創建的記為 B,在終端 B 內執行以下命令,監聽網絡請求:
- 隨后,在終端 A 中執行以下命令,觸發 ARP 協議更新:
- 其中,arp -d 命令可以刪除一條 ARP 映射記錄,這里需要將 替換為容器的網關 IP 地址,有許多方法可以獲取容器的網關地址:
-
- [容器內] 執行 route -n 命令,查看 Destination 為 0.0.0.0 時對應的 Gateway;
-
- [宿主機] 執行 docker network inspect bridge,查看 IPAM - Config - Gateway。
- 在終端 A 中有以下輸出,表示 ping 命令執行成功:
- 在終端 B 中,可以看到 ARP 協議包的內容:
- 可以看到,這里有兩次 ARP 請求與應答,第一次是容器 (192.168.1.2) 廣播查詢網關 (192.168.1.1) 的 MAC 地址,第二次是網關 (192.168.1.1) 廣播查詢容器 (192.168.1.2) 的 MAC 地址。
七、兩臺主機的通信過程
① 不同局域網的兩臺主機
- 以主機 ping 一個域名為例,過程如下:
-
- [主機] [應用層] 通過 DNS 協議獲取域名的 IP 地址;
-
- [主機] [網絡層] 構造 IP 數據包,源 IP 為本機 IP,目的 IP 為域名 IP;
-
- [主機] [網絡層] 根據路由表,選擇下一跳的 IP 地址,即當前局域網的網關;
-
- [主機] [鏈路層] 根據 ARP 表,查找網關 IP 的 MAC 地址;在 IP 數據包外面包一層 MAC 地址;
-
- [局域網] 根據 MAC 地址,上一步的報文最終會發送到當前局域網的網關;
-
- [網關] [網絡層] 網關查看數據包的目的 IP 地址,重復上述 2~3 步,繼續發給下一跳;
-
- [互聯網] 中間經過若干個下一跳主機,最終數據包發送到域名所在的網絡中心的網關;
-
- [網關] [網絡層] 網絡中心的網關查看數據包的目的 IP 地址,根據路由表發現目的 IP 對應的 Gateway 為 0.0.0.0,這表明目的機器和自己位于同一個局域網內;
-
- [網關] [鏈路層] 根據 ARP 表,查找目的 IP 的 MAC 地址,構造鏈路層報文;
-
- [局域網] 根據 MAC 地址,上一步的報文最終會發送到目的主機;
-
- [目的主機] [網絡層] 目的主機查看數據包中的目的 IP,發現是給自己的,解析其內容,過程結束。
② 同局域網內的兩臺主機
- 兩臺主機通過網線、網橋或者交換機連接,就構成了一個局域網。網橋或交換機的作用是連接多臺主機,隔離不同的端口,每個端口形成單獨的沖突域。當主機連接到網橋或交換機端口的時候,這些設備會要求主機上報 MAC 地址,并在設備內保存 MAC 地址與端口的對應關系。
- 同局域網內的兩臺主機進行通信時,只需要根據 ARP 協議獲取目的主機的 MAC 地址,構造鏈路層報文。報文會經過網橋或交換機,后兩者根據目的 MAC 地址,在 MAC 地址表里查詢目的端口,然后將報文從目的端口轉發給對應的主機。
- 注意:
-
- 交換機是鏈路層的設備,主要根據 MAC 地址進行轉發、隔離沖突域;不具有路由功能,不記錄路由表,這類設備也稱為二層交換機,如果只使用二層交換機、不使用路由器來構建局域網,需要為交換機和每臺主機分配同屬于一個子網的靜態 IP。
-
- 路由器工作在 OSI 的第三層網絡層,記錄路由表,并以此控制數據傳輸過程。
-
- 有些交換機也具有路由功能,記錄了路由表,能夠簡化路由過程、實現高速轉發,這類設備也稱為三層交換機。
③ 同局域網內的兩臺主機,目的主機有多個 IP
- 問題:如果目的主機 B 為自己新增了一個 IP,同局域網的主機 A ping 主機 B 的這個 IP 能 ping 通嗎?答案是不能,原因是主機 A ping 主機 B 時,根據路由表會將報文發給默認網關,但是網關的路由表里并沒有主機 B 新增加的 IP 信息。
- 可以做實驗驗證一下:分別啟動兩個容器 A、B(參數 --cap-add NET_ADMIN:打開網絡配置權限):
- 在容器 B 內執行以下命令,新增一個 IP 地址 192.168.1.55:
- 查看容器 B 的 IP 配置,可以看到新增了一個 lo:3 接口:
- 在容器 A 內嘗試 ping 192.168.1.55,發現無法 ping 通,解決辦法是修改容器 A 的路由表,執行以下命令,手動新增一條規則:
- 其中,destination 參數是容器 B 新增的 IP 地址;gateway 參數是容器 B 的默認 IP 地址,也就是上面 ifconfig 命令輸出的 eth0 接口的 IP 地址,這條規則的含義是“所有目的 IP 是 192.168.1.55 的數據包都發給 192.168.1.2”。
- 容器 A 內執行 route -n,查看路由表:
- 這個時候再從容器 A 中 ping 容器 B 的新 IP,就可以 ping 通:
- 如果在執行 ping 命令前,先在容器 B 執行 tcpdump,會看到如下輸出:
- 其中,192.168.1.1 是網關 IP,192.168.1.3 是容器 A 的 IP,81b3a9d0f060 是容器 B 的 ContainerID。上面的輸出依次表示:容器 A 通過 ARP 協議查詢網關的 MAC 地址;容器 A 通過 ARP 協議查詢容器 B 的 MAC 地址;容器 B 發出 ARP 應答;容器 A 發送 ICMP 請求、容器 B 應答。
七、總結
- Docker:
-
- 在 Docker 的各個命令中,<container_id> 和 <container_name>、<image_id> 和 <image_name> 可以互換;
-
- docker run 會重新創建一個新的容器,docker start 可以進入已經啟動的容器。
- Socket:
-
- 每個進程默認都有 0、1、2、255 四個文件描述符;
-
- 系統用 socket 來表示一個連接,socket 會綁定到進程的一個文件描述符,可以使用 open、write 系統調用來向遠程主機發送請求、讀取響應;
-
- Socket 通過 <源 IP、源 Port、目的 IP、目的 Port> 的四元組來區分,只要有一處不同,就是不同的 socket;
-
- netstat -natp:查看當前系統中的所有 socket。
- 路由表:
-
- route -n:查看路由表;
-
- Destination 為 0.0.0.0 時,Gateway 為默認網關;
-
- Gateway 為 0.0.0.0 時,Destination 為當前局域網的網絡地址;
-
- Genmask 為 255.255.255.255 時,Destination 為一個網絡中的一臺特定主機。
- ARP 表:
-
- arp -a:查看 ARP 緩存表;
-
- arp -d :刪除一條 ARP 記錄。
- 通信過程:
-
- 不同局域網的主機,數據包會在網絡層經過若干個下一跳 (當前局域網的默認網關 - 運營商網關 - 目的主機所在的數據中心網關),最終發送給目的主機所在的局域網:
-
- 同局域網內的主機,只需要通過 ARP 協議獲取目的主機的 MAC 地址,報文在數據鏈路層經由網橋或交換機轉發給目的主機;
-
- 交換機不具有路由功能,屬于二層設備;有些交換機為了提升效率而記錄路由表,屬于三層設備。
總結
以上是生活随笔為你收集整理的【网络通信与信息安全】之深入解析两台主机之间的通信过程和原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【数据结构与算法】之深入解析“省份数量”
- 下一篇: 【网络通信与信息安全】之深入解析进程之间