做視頻的素材什么網(wǎng)站好網(wǎng)絡(luò)推廣的話術(shù)怎么說
TCP/IP
網(wǎng)絡(luò)模型, 將網(wǎng)絡(luò)分為了四層:
之前的文章中以HTTP
和HTTPS
這兩個協(xié)議為代表, 簡單介紹了應(yīng)用層協(xié)議. 實際上, 無論是HTTP
還是HTTPS
等應(yīng)用層協(xié)議, 都是在傳輸層協(xié)議的基礎(chǔ)上實現(xiàn)的
而傳輸層協(xié)議中最具代表性的就是: UDP
和TCP
協(xié)議了. 以HTTP
為例, 在使用HTTP
協(xié)議通信之前, 是先需要建立TCP
連接的.
那么, 傳輸層協(xié)議的介紹就先從UDP
協(xié)議開始
再談端口號
在網(wǎng)絡(luò)通信中, 端口號可以標識主機中的唯一進程.
我們在使用UDP/TCP Socket
時, 都對服務(wù)器綁定過端口號. 在實際通信中, 當一個客戶端向服務(wù)器發(fā)送數(shù)據(jù)時, 服務(wù)器主機接收到數(shù)據(jù)之后, 操作系統(tǒng)會 根據(jù)報文中的端口號 將數(shù)據(jù)推送給對應(yīng)的進程
在TCP/IP
協(xié)議中, 通過 源IP、源端口、目的IP、目的端口、協(xié)議號 這樣一個五元組標識一個通信
IP
標記主機唯一性(用來尋找主機), 端口號
標記進程唯一性(用來選擇主機中的進程)
其中, 端口號
實際是傳輸層的內(nèi)容, 因為傳輸層向上就是應(yīng)用層了, 那么傳輸層就需要解決將數(shù)據(jù)交給上層哪一個進程的問題
而IP
則是解決報文在網(wǎng)絡(luò)中進行路由的問題, 需要通過 源IP和目的IP解決從哪來到哪去 的問題
實際上, 通過通過系統(tǒng)調(diào)用綁定的IP
和端口號
, 是會使用在TCP/IP
的不同層次中的: IP
使用在網(wǎng)絡(luò)層, 端口號
則使用在傳輸層
端口號劃分
端口號是16位的, 是因為傳輸層報頭中存在16位用來存儲端口號
那么端口號的范圍就是: 0~66535
其中0~1023
是知名端口號, 它特定分配給一些知名的應(yīng)用層協(xié)議使用, 比如:
-
SSH
服務(wù)器, 使用22端口 -
FTP
服務(wù)器, 使用21端口 -
TELNET
服務(wù)器, 使用23端口 -
HTTP
服務(wù)器, 使用80端口 -
HTTPS
服務(wù)器, 使用443端口 -
知名端口號在
/etc/services
文件中存儲著, 可以進行查看
這些知名端口號一般是不允許分配給其他服務(wù)的
而剩下的1024~65535
, 就是操作系統(tǒng)可以動態(tài)分配的端口號, 也可以被指定.
UDP
協(xié)議
之前介紹過, 主機發(fā)送數(shù)據(jù)通過不同的層級時, 不同的協(xié)議是會對數(shù)據(jù)添加報頭的
即之前我們使用sendto()
等一系列系統(tǒng)調(diào)用時, 并不是直接將數(shù)據(jù)發(fā)送到了另一套主機上, 而是由操作系統(tǒng)給網(wǎng)絡(luò)的下一層, 添加對應(yīng)的協(xié)議報頭:
不同協(xié)議會添加自己的報頭, 下面就介紹一下UDP
協(xié)議的格式
UDP
協(xié)議格式
UDP
協(xié)議的格式可以用一張圖來表示
從圖中可以看到出, UDP
協(xié)議報頭部分是固定的8個字節(jié)
, 剩下的則是應(yīng)用層傳輸過來的原始數(shù)據(jù), 即有效載荷
UDP
協(xié)議的報頭非常容易理解
首先, 這里有三個概念簡單理解一下:
傳輸層協(xié)議接收到來自上層的數(shù)據(jù)之后, 需要添加自己的協(xié)議報頭, 這個行為叫 封裝. 封裝之后, 就可以將數(shù)據(jù)繼續(xù)向下層傳輸
直到對應(yīng)主機的傳輸層收到封裝數(shù)據(jù)之后, 層協(xié)議需要對封裝數(shù)據(jù)進行 解包, 分別讀取數(shù)據(jù)和報頭
之后, 傳輸層還需要將獲取到的數(shù)據(jù)內(nèi)容 傳輸?shù)?指定應(yīng)用層進程的可用空間, 這個行為叫 分用
實際上,
TCP/IP
的每層都要考慮如何封裝、解包和分用的問題
UDP
協(xié)議使用固定長度的報頭長度, 就很好的解決了如何封裝和解包的問題
主機1在使用UDP
協(xié)議發(fā)送數(shù)據(jù)時, 只需要在原始數(shù)據(jù)前加上這8
字節(jié)的報頭就可以 實現(xiàn)封裝
對方主機獲取到數(shù)據(jù)之后, 只需要去掉前8個字節(jié), 就可以獲取有效載荷 實現(xiàn)解包
而, 分用的實現(xiàn) 就需要讀取UDP
報頭的內(nèi)容了
UDP
報頭中存在 16位的源端口號 和 16位的目的端口號. 當主機接收到UDP
報文之后, 讀取報頭中存儲的 16位目的端口號, 就可以知道要向哪一個應(yīng)用層進程的可用空間傳輸數(shù)據(jù)了. 即 可以實現(xiàn)分用
Linux中, 一切皆文件. 我們之前也介紹過
socket
套接字, 實際就是文件描述符當傳輸層協(xié)議知道應(yīng)用層對應(yīng)服務(wù)的端口號之后, 就可以找到對應(yīng)的進程, 然后就可以找到進程對應(yīng)的網(wǎng)絡(luò)文件, 將數(shù)據(jù)寫入到網(wǎng)絡(luò)文件的文件緩沖區(qū)中
進程服務(wù)就可以讀取數(shù)據(jù)了
而, 16位UDP長度
該作何理解呢?
16位UDP長度
表示, UDP
報文的整體長度, 而不是單指有效載荷的長度
我們知道, UDP
協(xié)議的特點之一是 面向數(shù)據(jù)報
面向數(shù)據(jù)報就表示, 每一個UDP
數(shù)據(jù)報都應(yīng)該是完整的. 兩個數(shù)據(jù)報之間是具有明顯的邊界的.
當接收主機接收到多個UDP
報文時, 可以通過讀取每個報頭中的UDP長度
來準確的獲取到完整的UDP
報文, 而不產(chǎn)生混亂
而, 16位檢驗和
則用于檢驗報文內(nèi)容是否出現(xiàn)了差錯等, 如果出現(xiàn)了差錯操作系統(tǒng)就會直接丟棄掉整個報文(這就是UDP
協(xié)議 不可靠 的表現(xiàn))
UDP
協(xié)議的不可靠是否看作一種缺點?不能將 不可靠 看作
UDP
協(xié)議的缺點, 不可靠 是UDP
協(xié)議的特點使用
UDP
協(xié)議通信, 數(shù)據(jù)報發(fā)生損壞會被直接丟棄. 這使UDP
協(xié)議可以使用在一些 對數(shù)據(jù)丟失有一定的容忍度的 一些特定的場景中, 比如: 視頻直播視頻直播可以容忍短暫的卡頓和畫面丟失, 但是需要保證直播內(nèi)容的持續(xù)輸出. 類似這樣的場景中,
UDP
協(xié)議可以很好的適配也就是說, 不可靠 不是一種缺點 而是一種特點, 可以用在更合適的場景中
UDP
不可靠, 也就意味這它不用像TCP
那樣 需要做一系列的保證數(shù)據(jù)可靠的操作和處理, 也就不用非常的復(fù)雜
總的來說, UDP
協(xié)議的格式就是8字節(jié)的UDP報頭
+原始數(shù)據(jù)
UDP協(xié)議報頭在Linux中的格式
那么, 使用UDP
協(xié)議通信時, 操作系統(tǒng)在傳輸層添加協(xié)議報頭時, 是以什么形式添加的, UDP
報頭的本質(zhì)是什么?
網(wǎng)絡(luò)協(xié)議棧TCP/IP
是在Linux內(nèi)核中實現(xiàn)的, Linux內(nèi)核是由C語言實現(xiàn)的
而Linux內(nèi)核中, UDP
報頭的實現(xiàn)就是一個結(jié)構(gòu)體:
這就意味著, 操作系統(tǒng)使用UDP
協(xié)議封裝數(shù)據(jù)時, 是以結(jié)構(gòu)體的形式添加的UDP
協(xié)議報頭, 因為UDP
協(xié)議報頭的格式在Linux內(nèi)核中的實現(xiàn)方式就是一個結(jié)構(gòu)體
那么, 我們使用UDP
協(xié)議創(chuàng)建網(wǎng)絡(luò)套接字時候, 需要將套接字bind()
到特定的端口上
然后在使用sendto()
進行發(fā)送數(shù)據(jù)時, 操作系統(tǒng)就會創(chuàng)建udphdr對象
并填充端口號、內(nèi)容以及檢驗和. 并將udphdr對象
以一定的形式拷貝到原始數(shù)據(jù)之前. 形成一個完整的UDP
報文
UDP
的緩沖區(qū)
在Linux系統(tǒng)中, 我們無論使用
UDP
還是TCP
進行通信, 無論是使用sendto()
還是write()
向網(wǎng)絡(luò)中發(fā)送數(shù)據(jù)實際上, 在函數(shù)執(zhí)行完畢之后都沒有直接將數(shù)據(jù)發(fā)送到網(wǎng)絡(luò)中, 而是在操作系統(tǒng)對數(shù)據(jù)進行處理了之后, 將數(shù)據(jù)放入到 發(fā)送緩沖區(qū) 中, 什么時候真正的發(fā)送出去, 由操作系統(tǒng)內(nèi)核決定
所以, 要理解一個東西:
sendto()
和write()
并不是發(fā)送的接口, 而是拷貝的接口. 調(diào)用這兩個接口, 都只是將數(shù)據(jù)拷貝到內(nèi)核中, 而不是制劑發(fā)送到網(wǎng)絡(luò)中或者直接寫入到內(nèi)核中接收數(shù)據(jù)也是一樣的, 操作系統(tǒng)接收網(wǎng)絡(luò)數(shù)據(jù)時, 從網(wǎng)絡(luò)層到傳輸層 也會將數(shù)據(jù)暫時存儲到接收緩沖區(qū), 等待內(nèi)核中傳輸層的接收、解包以及分用
實際上, UDP
協(xié)議在內(nèi)核中并沒有真正意義上的發(fā)送緩沖區(qū)
首先, 因為使用UDP
協(xié)議在發(fā)送數(shù)據(jù)時, 操作系統(tǒng)需要對數(shù)據(jù)進行的處理動作很簡單, 畢竟udphdr
是一個很簡單的只有8字節(jié)的結(jié)構(gòu)體, 只需要添加一個結(jié)構(gòu)體就可以. 并且UDP
協(xié)議不需要保證數(shù)據(jù)可靠性, 這也就意味著UDP
協(xié)議不需要將發(fā)送的數(shù)據(jù)在本地長時間維護, 也就不需要一個真正的發(fā)送緩沖區(qū)
這意味著, 當使用sendto()
將數(shù)據(jù)交給內(nèi)核時, 內(nèi)核會盡快的將數(shù)據(jù)發(fā)送到網(wǎng)絡(luò)層, 不需要在傳輸層存儲數(shù)據(jù)
不過, 雖然UDP
協(xié)議并沒有發(fā)送緩沖區(qū), 但 UDP
協(xié)議是有接收緩沖區(qū)的
也就是說, Linux系統(tǒng)內(nèi)核中維護有一塊空間 專門存儲收到的UDP
報文數(shù)據(jù), 并且 針對每一個UDP
套接字都會維護那一塊空間, 這就是內(nèi)核中UDP
的接收緩沖區(qū)
當操作系統(tǒng)接收到UDP
協(xié)議數(shù)據(jù)報時, UDP
協(xié)議會對UDP
數(shù)據(jù)報進行解包, 然后再將數(shù)據(jù)存儲到對應(yīng)UDP Socket
的接收緩沖區(qū)中, 這個過程實際就是UDP
協(xié)議對UDP
數(shù)據(jù)報解包和分用的過程
但是, UDP
協(xié)議是面向數(shù)據(jù)報的. 使用UDP
協(xié)議通信發(fā)送數(shù)據(jù)時, 都是以一個數(shù)據(jù)報一個數(shù)據(jù)報的形式發(fā)送的. 但是UDP
協(xié)議的接收緩沖區(qū)是 不保證 接收到UDP
數(shù)據(jù)報的順序 與 發(fā)送端發(fā)送UDP
數(shù)據(jù)報的順序 是一致的(即, 如果發(fā)送端按照12345的順序發(fā)送數(shù)據(jù)報, 接收端很可能并不是按照12345的順序接收到的)
UDP
數(shù)據(jù)報的發(fā)送順序與接收順序可能一致, 也體現(xiàn)了UDP
協(xié)議的不可靠性因為無法保證
UDP
數(shù)據(jù)報的接收順序, 所以如果有順序一致的需求, 那么接收端就需要對UDP
數(shù)據(jù)報進行重排序, 一般在發(fā)送方和接收方的應(yīng)用層實現(xiàn)
并且, 當UDP
協(xié)議接收緩沖區(qū)滿了之后, 再發(fā)送過來的UDP
數(shù)據(jù)報會被直接丟棄
UDP
協(xié)議發(fā)送端與接收端的 發(fā)送 與 接收 是互不影響的, 所以UDP
協(xié)議是全雙工的. 使用UDP
協(xié)議可以同時發(fā)送和接收數(shù)據(jù)報
UDP
報文大小
UDP
報文首部中, 有一塊16位的空間 是用來存儲UDP
報文總長度的
那么也就意味著: 一個UDP
報文, 最大也就 2的16次方個字節(jié), 即 64KB
(包括8字節(jié)
首部)
64KB
在現(xiàn)在是非常的小的. 那么, 如果使用UDP
協(xié)議傳輸大一點(超過64KB
)的文件時, 就需要在應(yīng)用層進行分包, 多次發(fā)送. 對應(yīng)的, 接收端同樣需要對接受的數(shù)據(jù)進行手動拼裝.
這就是關(guān)于UDP
協(xié)議簡單介紹的全部內(nèi)容了
感謝閱讀~