前幾節我們把網路通訊中的基礎都過了一遍,今天真正開始秀操作了。本節主要講解如何在應用層上去定義報文的結構體。良好的報文設計會讓今後的業務擴充套件變得輕鬆。順帶會講解一下位元組序。
可以發現最近的章節都把兩個小節合併成了一個。這裡最主要的原因是某些章節擬定標題的時候忘記注意篇幅考慮了,單獨拆除了不合適,顧合併之,以後的文章如果還有這種需要合併的不再做額外說明哈,你們那麼聰明看下標題肯定都懂的。o(∩_∩)o
章節
- Android與物聯網裝置通訊-概念入門
- Android與物聯網裝置通訊-資料傳遞的本質
- Android與物聯網裝置通訊-網路模型分層
- Android與物聯網裝置通訊-UDP協議原理
- Android與物聯網裝置通訊-TCP協議原理
- Android與物聯網裝置通訊-基於TCP/IP自定義報文
- Android與物聯網裝置通訊-什麼是位元組序
- Android與物聯網裝置通訊- 位元組報文組裝與解析
- Android與物聯網裝置通訊-利用UDP廣播來做裝置查詢
- Android與物聯網裝置通訊-實現遠端控制Android客戶端
- Android與物聯網裝置通訊-Android做小型伺服器
- Android與物聯網裝置通訊-除錯技巧
- Android與物聯網裝置通訊-並行序列與佇列
- Android與物聯網裝置通訊-資料安全
- Android與物聯網裝置通訊-心跳
- Android與物聯網裝置通訊-網路IO模型
目錄
- 自定義報文
- 位元組序
自定義報文
什麼是報文
實際上在前面幾個章節中,我們已經針對網路模型中的各個報文做過分析。如果不出意外的話,你已經認識了它們。
比較形象的解釋報文就像我們生活中隨處可見的收納盒。
它是用來裝東西的。(廢話!)
不同廠家生產的收納盒,擁有不同尺寸的大小和容器空間。雖然他們都叫收納盒(報文也一樣)。但是可以存放的物件也不一樣。
並且值得注意的是,一個收納盒往往已經給你劃分出了不同的區域,可以在他們的卡槽裡放置符合槽位的物件。這一點和我們的報文也是驚人的一致。倘若你把一個不屬於這個地方的東西強行塞入,就會弄壞它。在報文裡把內容放置在錯誤的欄位上也會引發災難。
總結一句話,報文就是用來為特定業務而設計成儲存內容的一種格式描述,正是有了它才能讓發收資料有了參考,而不會搞亂。說到這裡,你大概已經有完全明白了報文是什麼東西了吧,那麼我們開始定義一組報文。
定義
怎麼定義呢?當然不是憑空去寫。我們得先有業務嘛。
需求:
我們需要通過手機控制空調的開關、模式和溫度。請設計一下手機該對空調說傳送些什麼,空調怎麼去認識手機發過來的內容。
遙控的邏輯圖我偷個懶,就不畫,大家自行腦補。
什麼,你腦子補不過來?
就是你按下遙控器對著空調的那種場景呀。
欄位分析:
這裡的需求拆出來就三個功能:
-
開關: 屬於
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,小埠就是低位位元組在前高位位元組在後。大埠則正好相反是高位在前低位在後。
從阮一峰老師部落格裡看到一張很形象的圖。我貼一下:
解釋一下為什麼會出現兩種不同的位元組排列順序。因為計算機並不知道單獨一個位元組代表具體的意思,它只會傻傻的讀。計算機在設計的時候就採用了低位在前效率較高,但人們更加習慣高位在前的記法。所以就有了兩種模式。
而物聯網開發中有些硬體嵌入式開發會採用小端模式,而更上層應用開發者更傾向用大端模式,如果有一方沒有對此轉換處理就會造成資料老讀出來是錯的,而程式碼上看起來和協議實現一致的低階錯誤。
部分參考: 理解位元組序