前幾節咱們把網絡通訊中的基礎都過了一遍,今天真正開始秀操做了。本節主要講解如何在應用層上去定義報文的結構體。良好的報文設計會讓從此的業務擴展變得輕鬆。順帶會講解一下字節序。html
能夠發現最近的章節都把兩個小節合併成了一個。這裏最主要的緣由是某些章節擬定標題的時候忘記注意篇幅考慮了,單獨拆除了不合適,顧合併之,之後的文章若是還有這種須要合併的再也不作額外說明哈,大家那麼聰明看下標題確定都懂的。o(∩_∩)ojava
實際上在前面幾個章節中,咱們已經針對網絡模型中的各個報文作過度析。若是不出意外的話,你已經認識了它們。安全
比較形象的解釋報文就像咱們生活中隨處可見的收納盒。bash
它是用來裝東西的。(廢話!)服務器
不一樣廠家生產的收納盒,擁有不一樣尺寸的大小和容器空間。雖然他們都叫收納盒(報文也同樣)。可是能夠存放的物件也不同。網絡
而且值得注意的是,一個收納盒每每已經給你劃分出了不一樣的區域,能夠在他們的卡槽裏放置符合槽位的物件。這一點和咱們的報文也是驚人的一致。假若你把一個不屬於這個地方的東西強行塞入,就會弄壞它。在報文裏把內容放置在錯誤的字段上也會引起災難。spa
總結一句話,報文就是用來爲特定業務而設計成存儲內容的一種格式描述,正是有了它才能讓發收數據有了參考,而不會搞亂。說到這裏,你大概已經有徹底明白了報文是什麼東西了吧,那麼咱們開始定義一組報文。設計
怎麼定義呢?固然不是憑空去寫。咱們得先有業務嘛。調試
需求:code
咱們須要經過手機控制空調的開關、模式和溫度。請設計一下手機該對空調說發送些什麼,空調怎麼去認識手機發過來的內容。
遙控的邏輯圖我偷個懶,就不畫,你們自行腦補。
什麼,你腦子補不過來?
就是你按下遙控器對着空調的那種場景呀。
字段分析:
這裏的需求拆出來就三個功能:
開關: 屬於true
和false
邏輯。
模式: 有製冷、制熱、自動、換氣、除溼等。
溫度: 一個數值。
經過對功能進行分析,這裏說明咱們這個報文上設計字段須要知足三種功能。而且每種功能對應裏面的內容也是不一致的。有真假
、枚舉
和數值
,則對應的內容的長度也是不一致的。
好,我先給出我設計報文結構方案,一塊兒來看一下。
基本結構:
開關、模式、溫度
這裏和咱們第一節裏介紹的結構體很是相似。咱們接着往下看內容裏的可變長如何使用。
上表給出了功能碼對應的內容使用什麼結構和長度,以最簡單的開關爲列。咱們發送一組報文。在java裏那麼就會像下面這樣去組裝數據。
用java對象表示:
public class AirCondBaseStructure {
int len; //長度
byte sn[]; //序列號
byte code; //功能碼
byte data[]; //透傳數據
byte crc[]; //校驗
}
複製代碼
剩下的就是按照對應的功能,往這個對象裏塞入數據。(偏底層的叫法是結構體
)
最後發出去的數據就變成了這樣:
開關報文:
0x00 0x00 0x00 0x11 | 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x30 0x31 0x32 0x33 | 0x21 | 0x01 |0x57 0x9D
複製代碼
咱們根據上面報文表手動解析一把16進制數據:
長度: 0x00 0x00 0x00 0x11
int類型站四個字節,這裏0x11轉換成十進制就是17。
設備號: 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x30 0x31 0x32 0x33
佔13個字節,轉字符串後爲:1234567890123
功能碼:0x21
直接對應表中的開關功能。
內容: 0x01
直接對應表中的打開。
校驗和: 0x57 0x9D
驗算和發送端一致則爲數據正確。
根據上面的解析說明長度爲17,咱們來算一下設備號13字節+功能碼1字節+內容1字節+校驗和2字節
。正好長度等於17。
一樣的道理若是把這裏的功能碼替換成溫度調節,則致使長度發生變化。由於溫度的內容結構是shot類型會佔用兩個字節。以此類推,其他的報文也是如法制炮。
這裏給出其它兩組報文,讀者能夠嘗試本身動手解析一下試試,看能不能讀出來其中的意思?
模式報文:
0x00 0x00 0x00 0x11 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x30 0x31 0x32 0x33 0x22 0x01 0x57 0x6D
複製代碼
溫度調節報文:
0x00 0x00 0x00 0x12 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x30 0x31 0x32 0x33 0x23 0x00 0x1A 0x0D 0x95
複製代碼
留個做業,想掌握這門技能的同窗不妨能夠嘗試一下本身動手寫一寫組裝報文轉換成字節,再從字節轉換回對象。在下一個章節我將放出這部分的解析代碼。
從字面意思也能讀出來是字節排列順序。做爲在上層開發應用的同窗可能真的不多能實際接觸使用到。由於通常都是使用大端口表示法。java默認也是大端表示法。以致於你甚至都是第一次據說還有這種東西?
咱們先來看到底什麼是字節序:
拿int來舉例,咱們知道一個int佔用四個字節。那麼四個字節在計算機按字節表現的形式是怎麼排列的呢?
好比數字 int a= 201806;
就會像下面這樣
小端口(little endian) 表示法:0x00 0x03 0x14 0x4E
大端口(big endian) 表示法:0x4E 0x14 0x03 0x00
他們都表示數字201806,小端口就是低位字節在前高位字節在後。大端口則正好相反是高位在前低位在後。
從阮一峯老師博客裏看到一張很形象的圖。我貼一下:
解釋一下爲何會出現兩種不一樣的字節排列順序。由於計算機並不知道單獨一個字節表明具體的意思,它只會傻傻的讀。計算機在設計的時候就採用了低位在前效率較高,但人們更加習慣高位在前的記法。因此就有了兩種模式。
而物聯網開發中有些硬件嵌入式開發會採用小端模式,而更上層應用開發者更傾向用大端模式,若是有一方沒有對此轉換處理就會形成數據老讀出來是錯的,而代碼上看起來和協議實現一致的低級錯誤。
部分參考: 理解字節序