日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

【网络通信与信息安全】之深入解析两台主机之间的通信过程和原理

發布時間:2024/5/28 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【网络通信与信息安全】之深入解析两台主机之间的通信过程和原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、前言

  • 本文通過在 Docker 容器中執行命令,來深入了解兩臺主機之間的通信過程。閱讀完本文,您將熟悉以下內容:
    • Docker 的基本操作;
    • 創建 socket 并發送 HTTP 請求;
    • 路由表、路由決策過程;
    • ARP 協議、ARP 表更新過程;
  • 本文也是【網絡通信與信息安全】之深入解析從輸入一個URL到頁面加載完成的過程 的另一個角度的回答,將解決以下兩個問題:
    • 不同局域網的兩臺主機之間的通信過程;
    • 同局域網內的兩臺主機之間的通信過程。

二、準備 Docker 環境

① 下載鏡像

  • 關于 Docker 的基礎概念 (容器、鏡像等),可以參考:Docker 入門教程。
  • 在啟動 Docker 容器之前,需要先下載一個 Docker 鏡像,這里使用 Ubuntu 系統鏡像:
# docker pull <image> docker pull ubuntu

② 首次啟動

  • 從鏡像初始化并進入容器:
# docker run -it --name <container> <image> docker run -it --name ubuntu ubuntu
  • 參數說明:
    • -i:讓容器的標準輸入保持打開,從而能夠接受主機輸入的命令;
    • -t:為容器分配一個偽終端并綁定到容器的標準輸入上,-i 和 -t 結合,可以在終端中和容器進行交互;
    • –name:為容器起一個名字,方便后續操作該容器,否則每次都需要查找容器的 ContainerID。
  • 需要注意的是,每次 run 都會重新創建一個新的容器。
Docker 的各個命令中,<container_id><container_name><image_id><image_name> 可以互換,本文統一使用 <container><image> 來指代這些參數。

③ 配置環境

  • 在容器內執行以下命令,安裝必要的工具:
apt-get update apt-get install net-tools tcpdump iputils-ping
  • 安裝完成后,exit 退出容器。

④ 提交鏡像

  • 如果不小心刪除了容器,容器內的所有更改也將丟失,因此使用 commit 命令來保存容器中的更改:
# docker commit -m <message> --author <author_info> <container> [<repo>[:<tag>]] docker commit -m "Install packages" --author "elonz" ubuntu ubuntu:latest
  • 列出所有的鏡像,查看是否提交成功:
docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu latest a5d22784e35b About a minute ago 108MB
  • 如果有多余的無用鏡像,可以刪除:
# <image> 可以是上面的 REPOSITORY(image_name)IMAGE ID docker image rm <image>

⑤ 刪除容器

# docker rm <container> docker rm ubuntu
  • 查看當前所有容器,確認是否刪除成功:
docker container ls --all
  • 之后,重新啟動容器:
# docker run -it --name <container> <image> docker run -it --name ubuntu ubuntu
  • 到這里為止,就完成所有的環境安裝過程。

⑥ 退出容器

  • 如果需要退出容器,可以在容器內執行:
exit

⑦ 再次啟動容器

  • 如果容器未啟動 (Exited),執行 start 命令:
# docker start -i <container> docker start -i ubuntu
  • 如果容器已啟動 (Up),執行 exec 命令:
docker exec -it <container> /bin/bash
  • 容器是否啟動,可以通過 docker container ls --all 查看。

三、應用層

  • 當通過諸如 http.Get(“http://www.baidu.com/”) 這樣的 API 向服務器發送請求時,其底層實現無非以下幾個過程:
    • 通過 DNS 協議將域名解析為 IP 地址;
    • 通過操作系統提供的系統調用創建一個 socket 連接,這實際上是完成了 TCP 的三次握手過程;
    • 通過 socket 連接以文本形式向服務端發送請求,在代碼層面實際上是在向一個 socket 文件描述符寫入數據,寫入的數據就是一個 HTTP 請求。
  • 可以直接在終端實現這個過程,只需要以下三行命令:
exec 3<> /dev/tcp/www.baidu.com/80 printf "GET / HTTP/1.1\r\nHost: www.baidu.com\r\n\r\n" 1>& 3 cat <& 3

① 建立連接

  • 首先進入容器,查看當前系統中的文件描述符:
cd /dev/fd && lltotal 0 dr-x------ 2 root root 0 March 18 13:06 ./ dr-xr-xr-x 9 root root 0 March 18 13:06 ../ lrwx------ 1 root root 64 March 18 13:06 0 -> /dev/pts/0 lrwx------ 1 root root 64 March 18 13:06 1 -> /dev/pts/0 lrwx------ 1 root root 64 March 18 13:06 2 -> /dev/pts/0 lrwx------ 1 root root 64 March 18 13:06 255 -> /dev/pts/0
  • 系統當前只有 /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)。
  • 執行以下命令,建立一個連接:
exec 3<> /dev/tcp/www.baidu.com/80
  • 該命令創建了一個指向 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 連接:
cd /dev/fd && ll # 或者:ll /proc/$$/fdtotal 0 dr-x------ 2 root root 0 March 18 13:06 ./ dr-xr-xr-x 9 root root 0 March 18 13:06 ../ lrwx------ 1 root root 64 March 18 13:08 0 -> /dev/pts/0 lrwx------ 1 root root 64 March 18 13:08 1 -> /dev/pts/0 lrwx------ 1 root root 64 March 18 13:08 2 -> /dev/pts/0 lrwx------ 1 root root 64 March 18 13:11 255 -> /dev/pts/0 lrwx------ 1 root root 64 March 18 17:25 3 -> 'socket:[54134]' # 綁定在 3 號描述符

② 發送請求

  • 向 www.baidu.com 發送一個 GET 請求,只需要向 3 號文件描述符寫入請求報文 (格式):
printf "GET / HTTP/1.1\r\nHost: www.baidu.com\r\n\r\n" 1>& 3
  • 說明:> 3:重定向到名為 3 的文件;>& 3:重定向到 3 號文件描述符。

③ 讀取響應

  • 讀取 www.baidu.com 返回的響應:
cat <& 3 <!DOCTYPE html> <!--STATUS OK--><html> ... </html>

④ 關閉連接

# 關閉輸入連接: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:
exec 3<> /dev/tcp/www.baidu.com/80 # 在容器中手動創建一個 socket exec 4<> /dev/tcp/www.bing.com/80 # 同上,只是為了演示 netstat -natp Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 192.168.1.2:36384 110.242.68.4:80 ESTABLISHED 1/bash tcp 0 0 192.168.1.2:44960 202.89.233.100:80 ESTABLISHED 1/bash
  • netstat 命令 State 一列的取值:

  • 三次握手階段:
    • 客戶端:
TCP 連接狀態含義
SYN_SENT發送了連接請求,等待遠端的確認(三次握手第 1 步的結果)
ESTABLISHEDsocket 已經建立了連接
    • 服務端:
TCP 連接狀態含義
LISTEN監聽來自遠程應用的 TCP 連接請求
SYN_RECEIVED收到了連接請求并發送了確認報文,等待最終的確認(三次握手第 2 步的結果)
ESTABLISHEDsocket 已經建立了連接,這是數據傳輸階段的狀態
  • 四次揮手階段:
    • 客戶端:
TCP 連接狀態含義
FIN_WAIT1發送了連接終止請求,等待確認,通常持續時間較短
FIN_WAIT2發送了連接終止請求并收到了遠程的確認,等待遠程 TCP 的連接終止請求,這個狀態表明遠程在收到此 socket 的連接終止請求后,沒有立刻關閉它的 socket
CLOSING發送了連接終止請求后,收到了遠程的連接終止請求,正在等待遠程對連接終止請求的確認,這個狀態表明雙方同時進入關閉狀態
TIME_WAIT等待足夠的時間,以確保遠程 TCP 收到其連接終止請求的確認
CLOSEDsocket 已經沒有連接狀態
    • 服務端:
TCP 連接狀態含義
CLOSE_WAIT收到了遠程的連接終止請求,正在等待本地的應用程序發出連接終止請求
LAST_ACK等待先前發送的連接終止請求的確認,只有在發送連接終止請求前先收到了遠程的連接終止請求時,才會進入此狀態
CLOSEDsocket 已經沒有連接狀態

五、網絡層

  • 網絡層的功能是路由與尋址,數據包在網絡層是一跳一跳地傳輸的,從源節點到下一個節點,直到目的節點,形成一個鏈表式的結構。
  • 當數據包到達網絡中的一個節點時,該節點會檢查數據包的目的 IP 地址,如果不是自己的 IP 地址,就根據路由表決定將數據包發送給哪個網關。

① 路由表

  • 電腦、手機、路由集等都可以視為網絡層的一個節點 (或一臺主機),每個節點都有一個路由表。網絡層的節點通過路由表來選擇下一跳地址 (next hop address)。
  • Ubuntu 系統可以通過以下命令查看路由表:
route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 192.168.1.1 0.0.0.0 UG 0 0 0 eth0 192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
  • 路由表由一組規則組成,每條規則包含以下字段:
    • 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 網關“。
Destination Gateway Genmask Flags Metric Ref Use Iface 192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
  • 當 Genmask 為 255.255.255.255 時,代表這條規則的 Destination 不再是一個網絡地址,而是一個網絡中的一臺特定主機,這樣的規則可能對應一條點對點信道 (Point to Point Tunnel)。
  • 路由表中的規則可以手動指定,也可以通過路由協議來交換周圍網絡的拓撲信息、動態更新。

② 路由決策過程

  • 當一個節點收到一個數據包時,會根據路由表來找到下一跳的地址。具體而言,系統會遍歷路由表的每個表項,然后將目的 IP 和子網掩碼 Genmask 作二進制與運算,得到網絡地址,再判斷這個地址和表項的 Destination 是否匹配:
    • 如果只有一個匹配項,直接將數據包發送給該表項的網關 Gateway;
    • 如果有多個匹配項,則選擇子網掩碼最長的那個規則,然后發送給對應的網關;
    • 如果沒有匹配項,則將數據包發送給默認網關;
  • 上面最后一種情況實際上不會出現,因為路由表中包含了下面這條規則:
Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 192.168.1.1 0.0.0.0 UG 0 0 0 eth0
  • 任何目的 IP 和全 0 的 Genmask 作與運算,一定會得到全 0 的 Destination,這保證所有未知的目的 IP 都會發送給當前局域網的默認網關 (比如路由器),由后者決定下一跳的地址。

③ 案例分析

  • ping www.baidu.com 的路由決策過程;
  • ping 局域網的另一臺主機 的路由決策過程;
  • 對于以下的路由表,路由器會如何轉發目標 IP 為 128.75.43.16 和 192.12.17.10 的數據包?
Destination Gateway Genmask 128.75.43.0 A 255.255.255.0 128.75.43.0 B 255.255.255.128 192.12.17.5 C 255.255.255.255 default D 0.0.0.0
  • 結果分析:
    • 目標 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 localhost (192.168.1.1) at bc:5f:f6:df:d8:19 on en0 ifscope [ethernet] localhost (192.168.1.102) at 14:7d:da:32:8d:17 on en0 ifscope [ethernet]
  • 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 exec -it ubuntu /bin/bash # 宿主機執行
  • 為了便于表示,將一開始 docker start 創建的容器終端記為 A,docker exec 創建的記為 B,在終端 B 內執行以下命令,監聽網絡請求:
tcpdump -nn -i eth0 port 80 or arp
  • 隨后,在終端 A 中執行以下命令,觸發 ARP 協議更新:
# arp -d <ip> && ping www.baidu.com arp -d 192.168.1.1 && ping www.baidu.com
  • 其中,arp -d 命令可以刪除一條 ARP 映射記錄,這里需要將 替換為容器的網關 IP 地址,有許多方法可以獲取容器的網關地址:
    • [容器內] 執行 route -n 命令,查看 Destination 為 0.0.0.0 時對應的 Gateway;
    • [宿主機] 執行 docker network inspect bridge,查看 IPAM - Config - Gateway。
  • 在終端 A 中有以下輸出,表示 ping 命令執行成功:
PING www.a.shifen.com (110.242.68.3) 56(84) bytes of data. 64 bytes from 110.242.68.3 (110.242.68.3): icmp_seq=1 ttl=37 time=19.7 ms 64 bytes from 110.242.68.3 (110.242.68.3): icmp_seq=2 ttl=37 time=22.7 ms 64 bytes from 110.242.68.3 (110.242.68.3): icmp_seq=3 ttl=37 time=21.8 ms
  • 在終端 B 中,可以看到 ARP 協議包的內容:
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 17:04:43.847963 ARP, Request who-has 192.168.1.1 tell 192.168.1.2, length 28 17:04:43.848058 ARP, Reply 192.168.1.1 is-at 02:43:21:c4:75:58, length 28 17:04:53.009573 ARP, Request who-has 192.168.1.2 tell 192.168.1.1, length 28 17:04:53.009746 ARP, Reply 192.168.1.2 is-at 02:43:ac:11:00:02, length 28
  • 可以看到,這里有兩次 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:打開網絡配置權限):
docker run -it --name ubuntu --cap-add NET_ADMIN ubuntu # 容器 A docker run -it --name ubuntu_2 --cap-add NET_ADMIN ubuntu # 容器 B
  • 在容器 B 內執行以下命令,新增一個 IP 地址 192.168.1.55:
ifconfig lo:3 192.168.1.55/16
  • 查看容器 B 的 IP 配置,可以看到新增了一個 lo:3 接口:
ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 # 這里是默認 IPinet 192.168.1.2 netmask 255.255.0.0 broadcast 192.168.255.255ether 02:42:ac:11:00:03 txqueuelen 0 (Ethernet)RX packets 9 bytes 726 (726.0 B)RX errors 0 dropped 0 overruns 0 frame 0TX packets 0 bytes 0 (0.0 B)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536inet 127.0.0.1 netmask 255.0.0.0loop txqueuelen 1000 (Local Loopback)RX packets 0 bytes 0 (0.0 B)RX errors 0 dropped 0 overruns 0 frame 0TX packets 0 bytes 0 (0.0 B)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0lo:3: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 # 這里是新增的 IPinet 192.168.1.55 netmask 255.255.0.0loop txqueuelen 1000 (Local Loopback)
  • 在容器 A 內嘗試 ping 192.168.1.55,發現無法 ping 通,解決辦法是修改容器 A 的路由表,執行以下命令,手動新增一條規則:
# route add -host <destination> gw <gateway> route add -host 192.168.1.55 gw 192.168.1.2
  • 其中,destination 參數是容器 B 新增的 IP 地址;gateway 參數是容器 B 的默認 IP 地址,也就是上面 ifconfig 命令輸出的 eth0 接口的 IP 地址,這條規則的含義是“所有目的 IP 是 192.168.1.55 的數據包都發給 192.168.1.2”。
  • 容器 A 內執行 route -n,查看路由表:
Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 192.168.1.1 0.0.0.0 UG 0 0 0 eth0 192.168.1.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0 192.168.1.55 192.168.1.2 255.255.255.255 UGH 0 0 0 eth0
  • 這個時候再從容器 A 中 ping 容器 B 的新 IP,就可以 ping 通:
ping 192.168.1.55 PING 192.168.1.55 (192.168.1.55) 56(84) bytes of data. 64 bytes from 192.168.1.55: icmp_seq=1 ttl=64 time=0.589 ms 64 bytes from 192.168.1.55: icmp_seq=2 ttl=64 time=0.291 ms 64 bytes from 192.168.1.55: icmp_seq=3 ttl=64 time=0.669 ms ...
  • 如果在執行 ping 命令前,先在容器 B 執行 tcpdump,會看到如下輸出:
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 08:36:28.819409 ARP, Request who-has 192.168.1.1 tell 192.168.1.3, length 28 08:36:38.987179 ARP, Request who-has 81b3a9d0f060 tell 192.168.1.3, length 28 08:36:38.987296 ARP, Reply 81b3a9d0f060 is-at 02:43:ac:11:00:03 (oui Unknown), length 28 08:36:38.987537 IP 192.168.1.3 > 192.168.1.55: ICMP echo request, id 17, seq 1, length 64 08:36:38.987585 IP 192.168.1.55 > 192.168.1.3: ICMP echo reply, id 17, seq 1, length 64 08:36:40.019291 IP 192.168.1.3 > 192.168.1.55: ICMP echo request, id 17, seq 2, length 64 08:36:40.019410 IP 192.168.1.55 > 192.168.1.3: ICMP echo reply, id 17, seq 2, length 64 ...
  • 其中,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 地址,報文在數據鏈路層經由網橋或交換機轉發給目的主機;
    • 交換機不具有路由功能,屬于二層設備;有些交換機為了提升效率而記錄路由表,屬于三層設備。

總結

以上是生活随笔為你收集整理的【网络通信与信息安全】之深入解析两台主机之间的通信过程和原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。