三十天學不會TCP,UDP/IP網絡編程-UDP,從簡單的開始


如果對和程序員有關的計算機網絡知識,和對計算機網絡方面的編程有興趣,歡迎去gitbook(https://rogerzhu.gitbooks.io/-tcp-udp-ip/content/)star我的這一系列文章,雖然說現在這種“看不見”的東西真正能在實用中遇到的機會不多,但是我始終覺得無論計算機的語言,熱點方向怎么變化,作為一個程序員,很多基本的知識都應該有所了解。而當時在網上搜索資料的時候,這方面的資料真的是少的可憐,所以,我有幸前兩年接觸了這方面的知識,我覺得我應該把我知道的記錄下來,雖然寫的不一定很好,但是希望能給需要幫助的人多個參考。我的計划是用半年時間來寫完這一系列文章,這個標題也是我對太多速成文章的一種態度,好了,廢話不再多扯了,下面是其中的一節內容,更多內容可以去gitbook上找到。

 

這一節開始就進入傳輸層的部分了,也是內容最豐富可能更貼近於實際的部分了,很多書籍會從TCP開始介紹傳輸層,我覺得學習應該從簡單的到難的,所以我選擇從UDP先開始,況且是現有UDP協議並且發展至成熟然后再有的TCP。

UDP協議歷史

如果有人問我他想閱讀RFC,也就是我前面提過的互聯網的標准,有啥推薦的着手點。標准這種玩意兒大部分都又枯燥又長,真要看,睡着了是必須的,不看吧,總感覺與人談論的時候少了一種老子當年也是參加過啥啥的感覺。所以如果真想看看RFC到底都寫些啥,怎么寫,我十分推薦原始的UDP標准作為一個開始,UDP的RFC號是768,一共就3頁,完整而又嚴謹的闡述了UDP協議,雖然是英文,全看一遍也就最多30分鍾吧,而且有圖有真相,有文字有引用,作為一個着手點再合適不過。

UDP協議,學名User Datagram Protocol,Datagram這個名詞第一次在網絡中是在1970年,在一個很早期的網路設計CYCLADES中被一個叫Louis Pouzin提出。這個詞是data和telegram的一個組合,而這個CYCLADES是一個保證在可靠傳輸data而不保證可靠傳輸網絡的設計,簡單的來說就是這個網絡設計保證從放到一個端口上傳出去的數據可以完整無誤的到達另一端但是不保證一端想要傳輸的數據都能可靠的被放在端口上或者被另一端取出。這個Louis Pouzin提出這樣一個想法的原因之一就是他並不喜歡事情搞得很復雜,他認為沒有必要在一個已經具有可靠傳輸的機制上再疊加一層可靠傳輸的端到端的設計。

從目前看這個想法雖然是有弊端的,但是在當時並沒有那么大的網絡負載和網絡架構的時候,這是一種經濟而又行之有效的辦法,所以Datagram這個想法就被IP協議的設計者們所借鑒。

UDP特點

就如上一節所描述,Datagram提供的是一種不可靠的協議傳輸,最簡單的不可靠就是從A端的傳輸層發出的數據包不保證B端能接收到,或者按需要收到,B端也無需向A端表明自己是否收到。這有點像以前有一種群寄廣告的方法,寄廣告的一方並不知道他寄出的地址的人有沒有收到自己寄出去的廣告,而收到廣告更沒必要向寄出的人表明自己收到與否。

本質上為什么稱UDP為不可靠呢?因為他並不會保存發送出去的備份,這個特點在UDP中導致會有以下幾個方面的表現:

  1. 不能保證傳送出去的數據包不丟失,不重復
  2. 不能保證傳送出去的一系列數據包在接收端還是以相同的順序被讀取
  3. 不能保證傳送出去的數據包不出錯

另外UDP也沒有擁塞控制,這個專業名詞到TCP的時候會詳細描述,其實就是當路上流量很大甚至被堵的完全走不動的時候,UDP協議會不管這些東西,繼續向網絡上發送數據包。這樣會引起很多不良后果,比如丟包,造成網絡整個的崩潰。

那么UDP有這么多弱點為什么還作為傳輸層兩巨頭之一被廣泛運用呢?因為其長處也很明顯,就是經濟。所謂經濟就是UDP沒有復雜的建立連接,重傳重排,擁塞避免(這些名詞后面都會成為主角)等等,他只管在一端把數據發出去,同等情況下相對於要做這么多額外工作的協議肯定要快一些且“經濟”一些,那么有的應用對於數據包短暫丟失,亂序,錯亂都是能夠忍受的。最能理解的應用應該是網絡視頻,網絡電話之類的,對於一兩幀的丟失並不會引起用戶的抱怨。當然除了視頻,還有很多協議是建立在UDP之上的,他們中有的已經退出歷史舞台,有的依然天天都會為我們的上網默默的做出你看不到的工作,比如DHCP,DNS。甚至還有由於其沒有連接性的特點不得不使用UDP的場景,就是傳輸層廣播。

UDP數據包頭

UDP是工作在IP之上的,是一個應用層到IP的簡單接口,所以UDP整個的數據包是放在IP data部分的(可以回去再復習一下IP數據包頭格式)。而UDP數據包頭被設計的及其簡單而又有效,整個包頭只有8個字節,分為四個部分。這里我要用RFC里面的原圖了,這里我不得不說RFC里的圖是我最佩服的部分之一,各種各樣的圖示都用字符來繪畫出來,有的真的可以說讓我嘆為觀止。

 

從低字節到高字節依次是源端口,目的地端口,數據包長度,CRC校驗和。

如果讓我選傳輸層第一關鍵詞,我會選端口,應用層的各種協議的最重要的標識物之一就是傳輸層的端口。為什么在IP地址上還要加上端口這個概念呢?第一個作用是可以讓一個主機上的應用層可以有標識進行IP地址的復用,第二個就是分層思想里最重要的,每一層都處理每一層的事情,鏈路層看到MAC地址就知道這是鏈路層的數據包,網絡層看到IP地址或者類似的地址就知道自己該干活了,傳輸層也是一個道理。這樣數據才能沿協議棧不斷的上傳,而每一層也可以干自己的事情。

所以類似IP數據包頭有自己和對端的IP地址一樣,在UDP數據包頭中會含有自己的源端口號和對方的端口號。不過由於UDP是不需要對方返回響應消息的,所以源端口號可以填0表示不填。一個端口號是16位,所以一個IP地址最大的端口號是65535,但是很多端口號都是預先被保留用做特定的用途,這個在傳輸層雜項中我再稍微詳細的介紹一下。

接下來按照我前面所介紹的記這種數據頭格式的重要部分,就是長度,因為你需要讓對方知道我該讀多少的數據。

接下來的CRC校驗和比較有趣了,IP包頭的效驗和是頭部校驗和,只有頭部的數據會參與計算。而在UDP里,這個校驗和采用了一個偽頭部的概念。所謂偽頭部就是UDP在計算效驗和的時會把IP頭部的一些信息加入計算,具體的就是如下的信息:

 

其中包括,源IP地址,目的地IP地址,填充的8位0,協議名(UDP),UDP報文長度,為什么要這么做呢,標准里的解釋是通過IP地址可以確認該數據包是不是發送給本機,通過協議,可以確認有沒有誤傳。這樣做的好處是很明顯的,一是可以再一次確認關鍵字段沒有錯誤,而是使用偽首部而不是真正的把這些數據放在UDP數據包里可以減少負擔。

但是這個設計違背們一直強調的分層思想,在傳輸層不應該混入網絡層的東西,而且在網絡層的頭數據包CRC中已經讓兩個IP地址參與計算過了,這里再進行一次校驗,看起來有點多余。而我對這個問題也一直不知道最深的設計原理是什么,我的理解是可能在分層思想的時候隱含着雖然每一層都做自己的事情,但是上一層不應該天然相信下一層,在需要的時候他也可以對下一層的某些關鍵信息再做雙層確認。

對於這個校驗和,因為UDP是不保證可靠性的,在IPv4中是可以不填的,而以我遇到過的例子來看,大部分是不填的,或者填了對端也不會檢驗的,所謂多一事不如少一事的哲學思維看來也是通用的。

UDP數據實例

按照風格,再一次讓我們來看看現實抓包中的UDP數據包頭是什么樣子的。

 

 這個圖中可以看到,UDP是建立在IP紙上的,這里的源端口號是68,目的地端口號是67,長度329,這里開啟了checksum但是對端也不會確認計算的。最后一個stream index 是wireshark內部的編號,用來標識UDP,TCP數據流的序號,用中括號括起來的都不是UDP數據包中真正的內容。

好了,UDP就是這么簡單的一個協議,但是用處卻是很廣泛,從下一節開始,就從不同的幾個方面來介紹下UDP在每一台電腦上都會做的幾件事情。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM