C語言與物聯(lián)網(wǎng)之簡單通信協(xié)議
用C語言做物聯(lián)網(wǎng)網(wǎng)關(guān)開發(fā)時,經(jīng)常需要通過串口、485接口等從一些傳感器讀取數(shù)據(jù),由于網(wǎng)關(guān)設(shè)備和傳感器所處的環(huán)境復(fù)雜多樣,電磁干擾等常常會破壞傳輸?shù)臄?shù)據(jù),為了確保傳輸數(shù)據(jù)的可靠性,通常會采取一些策略,常用的策略:數(shù)據(jù)校驗(yàn)+超時重傳,具體過程如下:
發(fā)送方在發(fā)送數(shù)據(jù)時,在元數(shù)據(jù)的基礎(chǔ)上增加校驗(yàn)數(shù)據(jù)形成請求數(shù)據(jù)包(data pack),然后將請求數(shù)據(jù)包發(fā)送出去,并啟動守衛(wèi)計時器(Guard Timer)。
接收方在收到請求數(shù)據(jù)包后,以跟發(fā)送方相同的算法對元數(shù)據(jù)進(jìn)行計算得到校驗(yàn)數(shù)據(jù),然后跟收到的校驗(yàn)數(shù)據(jù)進(jìn)行比較,若相同,則說明數(shù)據(jù)可靠,可以使用;反之,說明數(shù)據(jù)被破壞,直接丟棄掉。若數(shù)據(jù)可靠,接收方以同樣的格式做成響應(yīng)數(shù)據(jù)包回復(fù)給發(fā)送方;若發(fā)現(xiàn)數(shù)據(jù)被破壞,接收方不回復(fù)任何數(shù)據(jù)。
如果發(fā)送方在守衛(wèi)計時器超時前正確地接收到了接收方回復(fù)的響應(yīng)數(shù)據(jù)包,則停止守衛(wèi)計時器,并進(jìn)行后續(xù)的處理;若發(fā)送方在守衛(wèi)計時器超時時仍未收到接收方回復(fù)的響應(yīng)數(shù)據(jù)包,則重新發(fā)送"1."中的數(shù)據(jù)包,如此反復(fù),直到正確發(fā)送或達(dá)到了重傳次數(shù)。
步驟1~3重點(diǎn)為了講述如何確保數(shù)據(jù)可靠傳輸,真實(shí)情景中為了能正確地斷包(識別數(shù)據(jù)包),通常會按照如下結(jié)構(gòu)來定義數(shù)據(jù)包:

- 包起始標(biāo)識:通常使用固定數(shù)據(jù),比如0xFA, 0xAA, 0xA5等;
- 元數(shù)據(jù)長度:根據(jù)元數(shù)據(jù)長度進(jìn)行斷包。比如:元數(shù)據(jù)長度占1字節(jié),校驗(yàn)數(shù)據(jù)占2字節(jié),當(dāng)元數(shù)據(jù)長度取值為10時,則數(shù)據(jù)包大小為14字節(jié);
- 元數(shù)據(jù):發(fā)送的或接收的,有一定格式或意義的應(yīng)用數(shù)據(jù);
校驗(yàn)數(shù)據(jù):按照某種校驗(yàn)算法(比如checksum,crc等)計算得到的值。
- #define MAX_DATA_LEN 100 /* 假設(shè)元數(shù)據(jù)的最大長度為100字節(jié) */
- typedef struct tag_data_pack {
- uint8_t sop; /* 包起始標(biāo)識,(Start Of Pack) */
- uint8_t len; /* 元數(shù)據(jù)長度,假設(shè)為1字節(jié) */
- uint8_t datas[MAX_DATA_LEN + 2]; /* 元數(shù)據(jù) + 2字節(jié)的校驗(yàn)數(shù)據(jù) */
- }data_pack_t;
總線式的通信中,通常還會在數(shù)據(jù)包中加入目標(biāo)設(shè)備的地址,以便于確定數(shù)據(jù)是發(fā)往總線上的哪個設(shè)備,數(shù)據(jù)包的參考結(jié)構(gòu)如下:

用C語言描述如下:
- #define MAX_DATA_LEN 100 /* 假設(shè)元數(shù)據(jù)的最大長度為100字節(jié) */
- typedef struct tag_data_pack {
- uint8_t sop; /* 包起始標(biāo)識,(Start Of Pack) */
- uint8_t addr; /* 目標(biāo)設(shè)備地址,假設(shè)為1字節(jié) */
- uint8_t len; /* 元數(shù)據(jù)長度,假設(shè)為1字節(jié) */
- uint8_t datas[MAX_DATA_LEN + 2]; /* 元數(shù)據(jù) + 2字節(jié)的校驗(yàn)數(shù)據(jù) */
- }data_pack_t;