[TOC]
# 數據包封裝
傳輸層及其以下的機制由內核提供,應用層由用戶進程提供,應用程序對通訊數據的含義進行解釋,而傳輸層及其以下處理通訊的細節,將數據從一臺計算機通過一定的路徑發送到另一臺計算機。
應用層數據通過協議棧發到網絡上時,每層協議都要加上一個數據首部(header),稱為封裝(Encapsulation),如下圖所示:

不同的協議層對數據包有不同的稱謂,在傳輸層叫做段(segment),在網絡層叫做數據報(datagram),在鏈路層叫做幀(frame)。
數據封裝成幀后發到傳輸介質上,到達目的主機后每層協議再剝掉相應的首部,最后將應用層數據交給應用程序處理。
# mac以太網幀格式
以太網的幀格式如下所示:

其中的源地址和目的地址是指網卡的硬件地址(也叫MAC地址),長度是48位,是在網卡出廠時固化的。可在shell中使用ifconfig命令查看,“HWaddr 00:15:F2:14:9E:3F”部分就是硬件地址。協議字段有三種值,分別對應IP、ARP、RARP。幀尾是CRC校驗碼。
以太網幀中的數據長度規定最小46字節,最大1500字節,ARP和RARP數據包的長度不夠46字節,要在后面補填充位。最大值1500稱為以太網的最大傳輸單元(MTU),不同的網絡類型有不同的MTU,如果一個數據包從以太網路由到撥號鏈路上,數據包長度大于撥號鏈路的MTU,則需要對數據包進行分片(fragmentation)。ifconfig命令輸出中也有“MTU:1500”。注意,MTU這個概念指數據幀中有效載荷的最大長度,不包括幀頭長度。
# ARP數據報格式
**如果查詢的ip不是局域網,那mac地址就填網關的**
在網絡通訊時,源主機的應用程序知道目的主機的IP地址和端口號,卻不知道目的主機的硬件地址,而數據包首先是被網卡接收到再去處理上層協議的,如果接收到的數據包的硬件地址與本機不符,則直接丟棄。因此在通訊前必須獲得目的主機的硬件地址。ARP協議就起到這個作用。源主機發出ARP請求,詢問“IP地址是192.168.0.1的主機的硬件地址是多少”,并將這個請求廣播到本地網段(以太網幀首部的硬件地址填FF:FF:FF:FF:FF:FF表示廣播),目的主機接收到廣播的ARP請求,發現其中的IP地址與本機相符,則發送一個ARP應答數據包給源主機,將自己的硬件地址填寫在應答包中。
每臺主機都維護一個ARP緩存表,可以用arp -a命令查看。緩存表中的表項有過期時間(一般為20分鐘),如果20分鐘內沒有再次使用某個表項,則該表項失效,下次還要發ARP請求來獲得目的主機的硬件地址。想一想,為什么表項要有過期時間而不是一直有效?
ARP數據報的格式如下所示:
1. Dest MAC:目的MAC地址
2.
Src MAC:源MAC地址
3.
幀類型:0x0806
4.
硬件類型:1(以太網)
5.
協議類型:0x0800(IP地址)
6.
硬件地址長度:6
7.
協議地址長度:4
8.
OP:1(ARP請求),2(ARP應答),3(RARP請求),4(RARP應答)

例子,發送個arp包
0806是mac協議那邊看類型
ff:ff:ff:ff:ff:ff是所有主機都要接受

# IP段格式
1. 版本:IP協議的版本。通信雙方使用過的IP協議的版本必須一致,目前最廣泛使用的IP協議版本號為4(即IPv4 )
2.
首部長度:單位是32位(4字節)
3.
服務類型:一般不適用,取值為0
4.
總長度:指首部加上數據的總長度,單位為字節
5.
標識(identification):IP軟件在存儲器中維持一個計數器,每產生一個數據報,計數器就加1,并將此值賦給標識字段
6.
標志(flag):目前只有兩位有意義。
*
標志字段中的最低位記為MF。MF=1即表示后面“還有分片”的數據報。MF=0表示這已是若干數據報片中的最后一個。
*
標志字段中間的一位記為DF,意思是“不能分片”,只有當DF=0時才允許分片
7.
片偏移:指出較長的分組在分片后,某片在源分組中的相對位置,也就是說,相對于用戶數據段的起點,該片從何處開始。片偏移以8字節為偏移單位。
8.
生存時間:TTL,表明是數據報在網絡中的壽命,即為“跳數限制”,由發出數據報的源點設置這個字段。路由器在轉發數據之前就把TTL值減一,當TTL值減為零時,就丟棄這個數據報。
9.
協議:指出此數據報攜帶的數據時使用何種協議,以便使目的主機的IP層知道應將數據部分上交給哪個處理過程,常用的ICMP(1),IGMP(2),TCP(6),UDP(17),IPv6(41)
10.
首部校驗和:只校驗數據報的首部,不包括數據部分。
11.
源地址:發送方IP地址
12.
目的地址:接收方IP地址

IP數據報的首部長度和數據長度都是可變長的,但總是4字節的整數倍。
對于IPv4,4位版本字段是4。4位首部長度的數值是以4字節為單位的,最小值為5,也就是說首部長度最小是4x5=20字節,也就是不帶任何選項的IP首部,4位能表示的最大值是15,也就是說首部長度最大是60字節。
8位TOS字段有3個位用來指定IP數據報的優先級(目前已經廢棄不用),還有4個位表示可選的服務類型(最小延遲、最大吞吐量、最大可靠性、最小成本),還有一個位總是0。
總長度是整個數據報(包括IP首部和IP層payload)的字節數。每傳一個IP數據報,16位的標識加1,可用于分片和重新組裝數據報。3位標志和13位片偏移用于分片。
TTL(Time to live)是這樣用的:源主機為數據包設定一個生存時間,比如64,每過一個路由器就把該值減1,如果減到0就表示路由已經太長了仍然找不到目的主機的網絡,就丟棄該包,因此這個生存時間的單位不是秒,而是跳(hop)。
協議字段指示上層協議是TCP、UDP、ICMP還是IGMP。然后是校驗和,只校驗IP首部,數據的校驗由更高層協議負責。IPv4的IP地址長度為32位。
# UDP數據報格式
源端口號:發送方端口號
目的端口號:接收方端口號
長度:UDP用戶數據報的長度,最小值是8(僅有首部)
校驗和:檢測UDP用戶數據報在傳輸中是否有錯,有錯就丟棄

下面分析一幀基于UDP的TFTP協議幀。
以太網首部
0000: 00 05 5d 67 d0 b1 00 05 5d 61 58 a8 08 00
IP首部
0000: 45 00
0010: 00 53 93 25 00 00 80 11 25 ec c0 a8 00 37 c0 a8
0020: 00 01
UDP首部
0020: 05 d4 00 45 00 3f ac 40
TFTP協議
0020: 00 01 'c'':''\''q'
0030: 'w''e''r''q''.''q''w''e'00 'n''e''t''a''s''c''i'
0040: 'i'00 'b''l''k''s''i''z''e'00 '5''1''2'00 't''i'
0050: 'm''e''o''u''t'00 '1''0'00 't''s''i''z''e'00 '0'
0060: 00以太網首部:源MAC地址是00:05:5d:61:58:a8,目的MAC地址是00:05:5d:67:d0:b1,上層協議類型0x0800表示IP。
IP首部:每一個字節0x45包含4位版本號和4位首部長度,版本號為4,即IPv4,首部長度為5,說明IP首部不帶有選項字段。服務類型為0,沒有使用服務。16位總長度字段(包括IP首部和IP層payload的長度)為0x0053,即83字節,加上以太網首部14字節可知整個幀長度是97字節。IP報標識是0x9325,標志字段和片偏移字段設置為0x0000,就是DF=0允許分片,MF=0此數據報沒有更多分片,沒有分片偏移。TTL是0x80,也就是128。上層協議0x11表示UDP協議。IP首部校驗和為0x25ec,源主機IP是c0 a8 00 37(192.168.0.55),目的主機IP是c0 a8 00 01(192.168.0.1)。
UDP首部:源端口號0x05d4(1492)是客戶端的端口號,目的端口號0x0045(69)是TFTP服務的well-known端口號。UDP報長度為0x003f,即63字節,包括UDP首部和UDP層pay-load的長度。UDP首部和UDP層payload的校驗和為0xac40。
TFTP是基于文本的協議,各字段之間用字節0分隔,開頭的00 01表示請求讀取一個文件,接下來的各字段是:
c:\qwerq.qwe
netascii
blksize 512
timeout 10
tsize 0
一般的網絡通信都是像TFTP協議這樣,通信的雙方分別是客戶端和服務器,客戶端主動發起請求(上面的例子就是客戶端發起的請求幀),而服務器被動地等待、接收和應答請求。客戶端的IP地址和端口號唯一標識了該主機上的TFTP客戶端進程,服務器的IP地址和端口號唯一標識了該主機上的TFTP服務進程,由于客戶端是主動發起請求的一方,它必須知道服務器的IP地址和TFTP服務進程的端口號,所以,一些常見的網絡協議有默認的服務器端口,例如HTTP服務默認TCP協議的80端口,FTP服務默認TCP協議的21端口,TFTP服務默認UDP協議的69端口(如上例所示)。在使用客戶端程序時,必須指定服務器的主機名或IP地址,如果不明確指定端口號則采用默認端口,請讀者查閱ftp、tftp等程序的man page了解如何指定端口號。/etc/services中列出了所有well-known的服務端口和對應的傳輸層協議,這是由IANA(Internet Assigned Numbers Authority)規定的,其中有些服務既可以用TCP也可以用UDP,為了清晰,IANA規定這樣的服務采用相同的TCP或UDP默認端口號,而另外一些TCP和UDP的相同端口號卻對應不同的服務。
很多服務有well-known的端口號,然而客戶端程序的端口號卻不必是well-known的,往往是每次運行客戶端程序時由系統自動分配一個空閑的端口號,用完就釋放掉,稱為ephemeral的端口號,想想這是為什么?
前面提過,UDP協議不面向連接,也不保證傳輸的可靠性,例如:
發送端的UDP協議層只管把應用層傳來的數據封裝成段交給IP協議層就算完成任務了,如果因為網絡故障該段無法發到對方,UDP協議層也不會給應用層返回任何錯誤信息。
接收端的UDP協議層只管把收到的數據根據端口號交給相應的應用程序就算完成任務了,如果發送端發來多個數據包并且在網絡上經過不同的路由,到達接收端時順序已經錯亂了,UDP協議層也不保證按發送時的順序交給應用層。
通常接收端的UDP協議層將收到的數據放在一個固定大小的緩沖區中等待應用程序來提取和處理,如果應用程序提取和處理的速度很慢,而發送端發送的速度很快,就會丟失數據包,UDP協議層并不報告這種錯誤。
因此,使用UDP協議的應用程序必須考慮到這些可能的問題并實現適當的解決方案,例如等待應答、超時重發、為數據包編號、流量控制等。一般使用UDP協議的應用程序實現都比較簡單,只是發送一些對可靠性要求不高的消息,而不發送大量的數據。例如,基于UDP的TFTP協議一般只用于傳送小文件(所以才叫trivial的ftp),而基于TCP的FTP協議適用于 各種文件的傳輸。TCP協議又是如何用面向連接的服務來代替應用程序解決傳輸的可靠性問題呢。
# TCP數據報格式
1. 源端口號:發送方端口號
2. 目的端口號:接收方端口號
3. 序列號:本報文段的數據的第一個字節的序號
4. 確認序號:期望收到對方下一個報文段的第一個數據字節的序號
5. 首部長度(數據偏移):TCP報文段的數據起始處距離TCP報文段的起始處有多遠,即首部長度。單位:32位,即以4字節為計算單位。
6. 保留:占6位,保留為今后使用,目前應置為0
7. 緊急URG: 此位置1,表明緊急指針字段有效,它告訴系統此報文段中有緊急數據,應盡快傳送
8. 確認ACK: 僅當ACK=1時確認號字段才有效,TCP規定,在連接建立后所有傳達的報文段都必須把ACK置1
9. 推送PSH:當兩個應用進程進行交互式的通信時,有時在一端的應用進程希望在鍵入一個命令后立即就能夠收到對方的響應。在這種情況下,TCP就可以使用推送(push)操作,這時,發送方TCP把PSH置1,并立即創建一個報文段發送出去,接收方收到PSH=1的報文段,就盡快地(即“推送”向前)交付給接收應用進程,而不再等到整個緩存都填滿后再向上交付
10. 復位RST: 用于復位相應的TCP連接
11. 同步SYN: 僅在三次握手建立TCP連接時有效。當SYN=1而ACK=0時,表明這是一個連接請求報文段,對方若同意建立連接,則應在相應的報文段中使用SYN=1和ACK=1.因此,SYN置1就表示這是一個連接請求或連接接受報文
12. 終止FIN:用來釋放一個連接。當FIN=1時,表明此報文段的發送方的數據已經發送完畢,并要求釋放運輸連接。
13. 窗口:指發送本報文段的一方的接收窗口(而不是自己的發送窗口)
14. 校驗和:校驗和字段檢驗的范圍包括首部和數據兩部分,在計算校驗和時需要加上12字節的偽頭部
15. 緊急指針:僅在URG=1時才有意義,它指出本報文段中的緊急數據的字節數(緊急數據結束后就是普通數據),即指出了緊急數據的末尾在報文中的位置,注意:即使窗口為零時也可發送緊急數據
16. 選項:長度可變,最長可達40字節,當沒有使用選項時,TCP首部長度是20字節

與UDP協議一樣也有源端口號和目的端口號,通訊的雙方由IP地址和端口號標識。
32位序號、32位確認序號、窗口大小稍后詳細解釋。
4位首部長度和IP協議頭類似,表示TCP協議頭的長度,以4字節為單位,因此TCP協議頭最長可以是4x15=60字節,如果沒有選項字段,TCP協議頭最短20字節。
URG、ACK、PSH、RST、SYN、FIN是六個控制位,本節稍后將解釋SYN、ACK、FIN、RST四個位,其它位的解釋從略。16位檢驗和將TCP協議頭和數據都計算在內。緊急指針和各種選項的解釋從略。
?
- c語言
- 基礎知識
- 變量和常量
- 宏定義和預處理
- 隨機數
- register變量
- errno全局變量
- 靜態變量
- 類型
- 數組
- 類型轉換
- vs中c4996錯誤
- 數據類型和長度
- 二進制數,八進制數和十六進制數
- 位域
- typedef定義類型
- 函數和編譯
- 函數調用慣例
- 函數進棧和出棧
- 函數
- 編譯
- sizeof
- main函數接收參數
- 宏函數
- 目標文件和可執行文件有什么
- 強符號和弱符號
- 什么是鏈接
- 符號
- 強引用和弱引用
- 字符串處理函數
- sscanf
- 查找子字符串
- 字符串指針
- qt
- MFC
- 指針
- 簡介
- 指針詳解
- 案例
- 指針數組
- 偏移量
- 間接賦值
- 易錯點
- 二級指針
- 結構體指針
- 字節對齊
- 函數指針
- 指針例子
- main接收用戶輸入
- 內存布局
- 內存分區
- 空間開辟和釋放
- 堆空間操作字符串
- 內存處理函數
- 內存分頁
- 內存模型
- 棧
- 棧溢出攻擊
- 內存泄露
- 大小端存儲法
- 寄存器
- 結構體
- 共用體
- 枚舉
- 文件操作
- 文件到底是什么
- 文件打開和關閉
- 文件的順序讀寫
- 文件的隨機讀寫
- 文件復制
- FILE和緩沖區
- 文件大小
- 插入,刪除,更改文件內容
- typeid
- 內部鏈接和外部鏈接
- 動態庫
- 調試器
- 調試的概念
- vs調試
- 多文件編程
- extern關鍵字
- 頭文件規范
- 標準庫以及標準頭文件
- 頭文件只包含一次
- static
- 多線程
- 簡介
- 創建線程threads.h
- 創建線程pthread
- gdb
- 簡介
- mac使用gdb
- setjump和longjump
- 零拷貝
- gc
- 調試器原理
- c++
- c++簡介
- c++對c的擴展
- ::作用域運算符
- 名字控制
- cpp對c的增強
- const
- 變量定義數組
- 盡量以const替換#define
- 引用
- 內聯函數
- 函數默認參數
- 函數占位參數
- 函數重載
- extern "C"
- 類和對象
- 類封裝
- 構造和析構
- 深淺拷貝
- explicit關鍵字
- 動態對象創建
- 靜態成員
- 對象模型
- this
- 友元
- 單例
- 繼承
- 多態
- 運算符重載
- 賦值重載
- 指針運算符(*,->)重載
- 前置和后置++
- 左移<<運算符重載
- 函數調用符重載
- 總結
- bool重載
- 模板
- 簡介
- 普通函數和模板函數調用
- 模板的局限性
- 類模板
- 復數的模板類
- 類模板作為參數
- 類模板繼承
- 類模板類內和類外實現
- 類模板和友元函數
- 類模板實現數組
- 類型轉換
- 異常
- 異常基本語法
- 異常的接口聲明
- 異常的棧解旋
- 異常的多態
- 標準異常庫
- 自定義異常
- io
- 流的概念和類庫結構
- 標準io流
- 標準輸入流
- 標準輸出流
- 文件讀寫
- STL
- 簡介
- string容器
- vector容器
- deque容器
- stack容器
- queue容器
- list容器
- set/multiset容器
- map/multimap容器
- pair對組
- 深淺拷貝問題
- 使用時機
- 常用算法
- 函數對象
- 謂詞
- 內建函數對象
- 函數對象適配器
- 空間適配器
- 常用遍歷算法
- 查找算法
- 排序算法
- 拷貝和替換算法
- 算術生成算法
- 集合算法
- gcc
- GDB
- makefile
- visualstudio
- VisualAssistX
- 各種插件
- utf8編碼
- 制作安裝項目
- 編譯模式
- 內存對齊
- 快捷鍵
- 自動補全
- 查看c++類內存布局
- FFmpeg
- ffmpeg架構
- 命令的基本格式
- 分解與復用
- 處理原始數據
- 錄屏和音
- 濾鏡
- 水印
- 音視頻的拼接與裁剪
- 視頻圖片轉換
- 直播
- ffplay
- 常見問題
- 多媒體文件處理
- ffmpeg代碼結構
- 日志系統
- 處理流數據
- linux
- 系統調用
- 常用IO函數
- 文件操作函數
- 文件描述符復制
- 目錄相關操作
- 時間相關函數
- 進程
- valgrind
- 進程通信
- 信號
- 信號產生函數
- 信號集
- 信號捕捉
- SIGCHLD信號
- 不可重入函數和可重入函數
- 進程組
- 會話
- 守護進程
- 線程
- 線程屬性
- 互斥鎖
- 讀寫鎖
- 條件變量
- 信號量
- 網絡
- 分層模型
- 協議格式
- TCP協議
- socket
- socket概念
- 網絡字節序
- ip地址轉換函數
- sockaddr數據結構
- 網絡套接字函數
- socket模型創建流程圖
- socket函數
- bind函數
- listen函數
- accept函數
- connect函數
- C/S模型-TCP
- 出錯處理封裝函數
- 多進程并發服務器
- 多線程并發服務器
- 多路I/O復用服務器
- select
- poll
- epoll
- epoll事件
- epoll例子
- epoll反應堆思想
- udp
- socket IPC(本地套接字domain)
- 其他常用函數
- libevent
- libevent簡介