實際應用中,TCP/IP協議棧是如何工作的?

TCP/IP協議棧中各個協議的作用及其結構,題主已經學懂了。但是對於實際應用中,各個協議如何協同工作的,還是有些不理解,希望大佬們能賜教:

1、以瀏覽器請求一張大圖片為例,說下按我的理解吧:先三次TCP握手(NO1 NO2 NO3),然後發出一個http請求(NO4),服務端向客戶端確認收到了請求(NO5),服務端開始發送圖片,實際上是一個http響應,但是因為該響應消息很大(圖片很大),所以該http響應消息被TCP分段(由TCP協議棧進程進行分段,瀏覽器不作處理)然後再發送(NO6~NO81,其中有服務端發送的分段,也有客戶端的確認),客戶端收到所有分段後,重組為一個http響應報文,交付給瀏覽器,瀏覽器確認並斷開連接(NO83 NO84)

以上理解是否有誤?

2、關於wireshark的疑惑:網上好多文章說wireshark是針對網卡,抓取傳輸層的包,這種說法是否正確?

我在使用wireshark的時候發現,對於ping,沒有傳輸層流量,只有網路層icmp分組消息,也可以被wireshark捕捉並顯示為icmp包的啊,並不支持這種說法;對於比較小的http消息,其在軟體中顯示就是一條,但可以對應查看到TCP頭部、IP頭部,支持這種說法;對於較大的http消息,被切割成了多個tcp分段,所以會顯示成多個tcp條目,只有最後一條因為包含http頭部,所以顯示為http(NO82),也是支持這種說法的。

//為了方便閱覽,去掉了一些時間源目IP列,高埠是本地瀏覽器,80是目標伺服器。

//該環境使用了openvpn,監聽的是openvpn的虛擬網卡,所以包內容看起來有些不一樣。。。特此說明下。


問題一:對TCP的理解基本上是對的,但是有一個地方是不準確的。

TCP不會對接收到的segments,拼接成一個文件再讓應用程序取走,這是不對的!

第一:如果這麼做,一個大文件很容易就將接收方的接收緩存耗盡,壓根沒有辦法再接收後續數據。

第二:TCP根本不理解segment里是什麼內容,在這個問題里,它們只是1397位元組的segment,至於誰是第一個segment、誰是第二個,TCP是知道的,TCP可以將segment按序排隊放入接收緩存,等待應用程序取走(非同步操作),這是TCP唯一能做的!

TCP不會做拼接http報文的工作(因為壓根不懂),TCP只保證將接收到位元組流按序提交給瀏覽器就可以了。

這裡的客戶端應用程序為瀏覽器,瀏覽器讀取了segment 1、2、3....,瀏覽器通過第一個segment就明白接下來傳輸的是一個多少位元組長的文件。瀏覽器根據文件的長度,從文件的起點一直拼接到長度指示的終點。當文件完整得到了,瀏覽器就在頁面上呈現給用戶。

問題二:wireshark內部如何實現,除了核心開發人員,沒有人可以知道細節。

抓包軟體大同小異,如果把抓包軟體比作撈魚的漁網,這個漁網能撈多少魚,完全取決於是在TCP/IP協議棧撈魚,還是在網卡上撈魚。為了更好說明這個問題,做一個實驗:

實驗:Ping 127.0.0.1

之所以做這個實驗,是想證明一點,主機與自己通信,直接在TCP/IP協議棧里完成,而無需數據鏈路層的參與。以下是整個實驗過程:

分別使用windows 自帶的ping ,以及第三方的nping,分別ping 127.0.0.1,這個127.0.0.1就是windows主機自己的loopback IP,只用於主機內部進程間通信。

抓包顯示,數據鏈路層是空的,所以可以推測,主機內部進程之間通信,並不需要經過物理網卡。

為了證明Ping報文沒有經過物理網卡,在物理網卡上抓包,結果沒有抓到這些Ping包。

有同學會說,127.0.0.1是一個軟體環回介面,沒有硬體MAC,所以Ping報文才不會有硬體網卡的參與。

如果Ping 自己硬體網卡綁定的IP地址呢?

本機的網卡綁定的IP = 10.1.4.2,Ping 10.1.4.2 一探究竟。

同樣,也沒有乙太網協議頭,自然就沒有 Source / Destination MAC。

為了證明Ping報文沒有經過物理網卡,在物理網卡上抓包,結果也沒有抓到這些Ping包。

通過這個實驗,可以得到這樣的結論:

操作系統的協議棧,當發現IP報文的Destination IP ==主機任何介面IP時,不管是127.0.0.1,還是這裡的10.1.4.2,一律環回(loopback) 處理。

將需要做loopback的報文,直接從IP協議棧的發送緩衝區copy到接收緩衝區,造成的結果就是,這些IP報文彷彿是從硬體網卡接收到的一樣。

由於IP報文在IP協議棧(三層)已經掉頭向上走,而不會向下走,所在在硬體網卡上是捕獲不到的。

抓到127.0.0.1的ping包,是因為wireshark捕獲介面是軟體環回介面適配器,工作在TCP/IP協議棧(三層及以上)內,所以能夠把TCP/IP協議棧內流動的流量複製下來,自然wireshark能夠捕獲到。

而當wireshark捕獲介面是硬體網卡適配器,工作在硬體網卡(二層)內,而ping 127.0.0.1的流量不會下放到基層(二層),網卡自然看不到這些流量,所以wireshark不會捕獲到。

更多內容請閱讀公眾號文章:

實際應用中,TCP/IP協議棧是如何工作的??

mp.weixin.qq.com圖標


1、TCP 協議要理解為一個雙向流,有粘包和拆包的問題。也就是說,有可能客戶端多次寫少量數據,操作系統合併成一個包發出去,也可能客戶端寫一次大量數據,操作系統拆成多個包發出去。接收方收到 TCP 數據包的時候,並不會按照發送方每次寫數據的量進行合併,只會把數據一段一段地交給瀏覽器,由瀏覽器根據 HTTP 協議的約定來判斷數據的邊界。

推薦前幾天看到的一篇文章 :

炮打TCP - 關於一而再再而三的粘包拆包問題的大字報?

www.ideawu.net

2、wireshark 一般是通過 pcap 庫捕包的,這個問題其實是 pcap 庫的問題。pcap 庫默認是從鏈路層數據開始抓的,所以在真實網卡上可以抓到 arp 、 stp 等二層協議的數據包。你抓的是虛擬網卡上的數據包,可能會比真實網卡少一些類型。


車小胖回答的比我好,不過我還是有點需要補充。

wireshark和tcpdump很類似。因此我以linux平台的抓包軟體為例回答第二點。

e1000網卡驅動中,下半部回調函數為net_rx_action,該函數最終調用到__netif_receive_skb_core()函數(低版本可能為__netif_receive_skb())。此函數內用到了兩個全局變數,ptype_base和ptype_all。這兩個結構體在內核中存儲情況如下圖:

可以看到,ptype_base為一個hash表,而ptype_all為一個雙向鏈表。兩個結構中的元素都用結構體packet_type表示。

需要注意的是dev參數,此參數表明了此協議只處理來自dev指向的device的數據。當dev=NULL時,協議處理來自所有device的數據。這樣,當註冊自己的協議時,就可以指定自己想要監聽或者接收的device。

__netif_receive_skb_core()函數主要工作為:

  1. 處理NETPOLL、網卡綁定、入口流量控制、橋接、VLAN

2. 遍歷嗅探器(ETH_P_ALL)鏈表ptype_all。對於每個註冊的sniffer,調用它的處理函數

packet_type-&>func(),例如tcpdump。

3. 賦值skb-&>network_header,根據skb-&>protocol從三層協議哈希表ptype_base中找到對應的

三層協議。如果三層協議是ETH_P_IP,相應的packet_type為ip_packet_type, 協議處理函數為ip_rcv()。

結論:

從以上三步清晰可見,抓包軟體工作在協議棧的驅動層,或者說二層解析之前(第三步操作可以看作二層解析)。

車小胖同學提到某些包不過驅動層,這個我不是太清楚。一般socket用於跨主機通信,跨主機時不存在目的是127.0.0.1的情況,因此暫不考慮。


看了一下目前的幾個回答, 作為一個自以為在這方面理解比較深的,從原理和自身的理解來直觀的問答一下:

問題一:協議棧是分層的

對於流程分析基本是對的,但是原理還是有很大偏差。

協議棧分層應該大家都知道,但是怎麼理解呢?

發送HTTP請求,應用層會向TCP層發送數據報文。TCP層看到的是數據,它是根據自己的機制來依次發送報文的。你說的分段應該是把MSS搞混了,TCP是面向位元組流的,不存在分片;然而它每次發包會參考MSS,以MSS作為單位來發送報文,這只是底層協議的MTU。

接收HTTP請求,應用層會去TCP層讀書數據報文,將TCP層中的數據組合成HTTP協議報文,這是和TCP層沒有關係的。

所以,HTTP請求過大,跟TCP沒關係的。HTTP發送過大的包,那就需要HTTP進程不停的向TCP協議棧發包,直到發完;(而不是把報文丟給TCP,TCP自己去拆包),接收同理。在高並發編程中,發送和接收,在微觀層面基本決定了網路事件庫的性能。

問題二:抓包工具是抓的網卡數據報

網卡的數據包,這就是3層以上協議報文(IP層以上)。如果只有兩層協議,直接能查到對方的MAC地址的。

而至於抓取的報文怎麼過濾,那是看過濾條件怎麼設置。

題外話,對於車小胖的「wireshark內部如何實現,除了核心開發人員,沒有人可以知道細節」

抓包工具,抓包沒有什麼原理的,就是把網卡上的數據流按照你的抓取條件copy過來(這就是抓包條件和你直接抓網卡在wireshark中過濾,抓的報文是不一樣的)。wireshark主要是有協議解析,流量分析這些東西的。

比如你在window上設置了一下網卡的功能(分擔組包),你可以看到發給網卡的包有些細節並不符合TCP協議。

至於說向本機發送報文,這不應該去糾結驅動和數據鏈路層。

網路都是全雙工的,IP層有發送邏輯和接收邏輯。通常的發送報文中,IP層根據ARP查到目的地址,發送邏輯將報文發送到對方的接收邏輯中。而本地通信,查到的目的地址是本機,可以直接交付給本地IP層接收邏輯。


針對問題一:

1. 不會有NO5這個玩意的存在。

2. TCP/IP協議中的TCP協議可以保證數據有序到達

3. http協議基於TCP數據包組裝圖片(分片也好,不分片也罷)

4. 瀏覽器基於HTML語言(協議)顯示圖片

5. 眼睛根據人類視覺協議感知圖片,尼瑪是張小黃圖


lwip有全套的實現


嚴格來說抓的是二層的幀,圖一滑鼠選中的frame50,就是一個證明,arp協議也能抓到是另一個證明。


wireshark當然是抓二層包,你沒看見過arp?


bsd源碼歡迎你,詳見sys/net和sys/netinet。

ps:辣雞gpl有毒。

(逃。。。


推薦閱讀:

HTTP的post和get
http是應用層,ip是網路層,那麼http請求頭部的client ip是怎麼獲取到的呢?
想寫個web伺服器,用Go語言實現,需要有哪些前提知識呢?
Logtail技術分享(一) : Polling + Inotify 組合下的日誌保序採集方案
服務端處理耗時請求(發郵件/壓縮圖片/抓取網頁)一般有幾種方法?

TAG:互聯網 | 計算機網路 | 計算機科學 | HTTP | TCPIP |