close

前些天跟大家解釋了如下代碼:

offset=len/64+!!(len%64);

並且跟大家詳細聊了一下其中的!!操作,然而這段代碼的主要功能還是為了進行分包處理,既然是分包自然而然就會想到一種常用的分包處理方法,這也是本文的重點。

數據分包在嵌入式軟件開發中算是一種非常常見的處理,其主要原因還是硬件上的各種限制,不得已而為之,特別是在通信協議的定製過程中尤為常見。

1

傳輸限制

玩過各種通信協議的朋友都知道,像非常多的通信方式都是以數據幀的形式來進行傳遞,不同的通信方式因各方面的因素又存在一個最大傳輸字節數的限制,考慮到穩定性、容錯性等等對單次發送的數據長度進行限制,又或者所接收的設備其內存資源有限,不足以接收、處理過長的數據包。

像zigbee這樣的物理層每幀最大只能傳輸127個字節,通過每層不斷的封包到應用層後每包才100個字節。當上層用戶協議的數據包過大,無法一次性傳輸,就只能分包或者分組下發,最終接收方組包後解析提取數據。

2

分包設計的考慮

有些朋友該說了,我就不喜歡搞大包發送,使用短包,然後通過不同的標識進行不同數據位的定義,簡單很多。

當然長包與短包並沒有本質上的區別,其目的都是傳輸數據,但在實踐的過程中還是會遇到居多處理上的區別:

數據的同步性方面:

比如當通信的設備轉速超了,同時報了一個故障碼,如果採用短包上傳,很可能故障碼和轉速位於不同的數據包中,當數據包丟包或許是亂序,就會導致當接收到故障碼的時候,此時超標的轉速值已經丟失或者延時等,有概率不能準確獲得故障時的超標轉速。

而使用長包,只需要發送方能夠保證打包的時候同步,那麼接收方就可以同步獲得相應的數據。

通信協議設計自由度方面:

在設計協議的時候,長包會更加的自由,大多數情況都不需要考慮大數據傳輸的占位問題,甚至在編碼上直接copy結構體發送也是相當方便的。

3

計算包數問題

既然長包的設計相對比較方便。那分包處理是少不了的?

分包還不簡單?

要發100個字節的數據,每次只能發15個,那發送7包就可以了,直接編碼,代碼如下:

SendPack=SendNum/PackNum;if(SendPack%PackNum)SendPack++;

這算是常規操作,如果覺得有點難度,還要多敲敲代碼。

一般用C語言比較久的朋友都想去簡化這種操作,畢竟實現一個簡單的功能需要兩行代碼,強迫症,忍不了~

就有了本文開頭的!!處理方式,或者如下處理也是一樣的:

#include<stdio.h>#definePackNum(total,single)(total/single+((total%single)?1:0))intmain(void){printf("packNum:%d\r\n",PackNum(100,15));printf("packNum:%d\r\n",PackNum(150,15));printf("packNum:%d\r\n",PackNum(200,15));printf("packNum:%d\r\n",PackNum(5,15));printf("hellobug~\r\n");return0;}

僅僅只是秀了一下C語言的幾個小技巧罷了,並沒有實質性的改善。

很明顯,本文的重點並不是介紹如上兩種辦法,而是如下更加高效的代碼:

PackNum=(total+(singleNum-1))/singleNum;

對於一些以往沒有使用的朋友或許有點懵,這是嘮叨幾句:

該表達式主要是利用了取整的特性來達到+1的目的。

直接除單包個數,不能整除的情況,結果都會少1,比如10/6,應該是2包,而由於最終除法結果只能是1。

所以通過補償(singleNum - 1)後,結果就分兩種情況:

1、原本能夠整除的數,補償後無法整除,結果與之前一致;

2、原本不能夠整除的數,其餘數必然在【1~(singleNum- 1)】之間,所以補償以後,其餘數範圍在【singleNum~(singleNum+ singleNum- 2)】,則其結果為整除部分+1。

與我們分包個數是一致的,相當巧妙。

4

擴展

這種方法不僅僅只是用於通信的分組中,把思維進一步泛化。

只要是類似分組的處理都可以使用該算法。

比如內存的分區,flash的設計上都是一個扇區一個扇區的分布。

現在想分配整數個扇形區域用於存儲某些數據,每一個扇區512個字節,存儲2000個字節的數據,該分配幾個扇區?

我相信你已經有答案了~


來源:最後一個bug
版權歸原作者所有,如有侵權,請聯繫刪除。

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 鑽石舞台 的頭像
    鑽石舞台

    鑽石舞台

    鑽石舞台 發表在 痞客邦 留言(0) 人氣()