本報文格式不能處理粘包問題,因為處理粘包問題的成本太高,會極大的降低服務端的處理效率以及增加記憶體消耗,如果傳輸速度很高,建議使用
udp,
udp傳輸速度快,並且應用層做響應,增加重傳機制可以有效的保證資料的可靠性,目前我做的
rtu公升級等功能都是使用
udp完成,伺服器端開銷小,並且不會粘包。
通訊建議:不要做什麼握手機制,直接傳送資料,伺服器收到了就響應,收到響應後就結束通訊,握手增加耗電又增加流量消耗,並且在
gprs
1個來回,特別是之前用過
mqtt
多了幾個來回,太浪費通訊資源了。
使用hex
格式的通訊協議非常高效,不管是傳送打包還是接收拆包,
1個結構體就能搞定,無需乙個位元組乙個位元組解析,如果用字串
json
方式,使用微控制器作為客戶端就很為難了,一般記憶體不會很多,並且解析
json
需要的記憶體會非常多。
報文全部使用小端模式,便於
c語言處理。
注:由於我之前做了乙個支援
10w個裝置的資料解析軟體,其實占用的記憶體非常少,並且對
cpu消耗很低,我們使用了乙個很低端的伺服器就能做到每秒
1k條以上的資料處理,並且每條資料都在
1秒內得到響應,剛開始的時候還好,後面因為裝置越來越多,導致伺服器搜尋裝置變得很漫長(我的裝置資料都是放到記憶體中,使用了乙個指標陣列進行管理),由於裝置會動態的增加,不能對序列號進行排序,因此查詢裝置的索引時間將會不可控,解析一條資料非常快,儲存是非同步的,有
1w條的快取,但是唯獨查詢裝置這個看似簡單的過程變得非常複雜,由於之前的協議我沒有增加索引,我只能對裝置進行分組,我建了
1w個指標陣列,根據裝置尾號後
4位進行分組,這樣會增加幾十兆的記憶體消耗,但是查詢卻變得非常迅速。通過這個事情之後,我決定在協議中直接增加索引,服務端收到索引後直接取出當前裝置的配置與
sn進行對比,如果相同就直接解析儲存資料,如果不相同就進行查詢即可,沒有就進行新建,最後建議將裝置分組與協議中增加索引進行整合,集各自的優點,可以最大限度的提高資料的解析能力,當每個裝置都通訊一次之後,解析任何乙個裝置上傳的資料的時間都是一樣的,並且是最小的。
禁忌:解析資料是千萬不要把配置什麼的都放到資料庫,資料庫相比記憶體實在是慢太多了,而且時間不可控,資料庫本身就不是非常可靠,建議將資料庫操作做非同步處理,中間用
fifo
通訊,這樣資料解析執行緒可以以最高效的方式執行(乙個執行緒輕鬆解析成千上萬條資料,通過增加乙個執行緒可以提高
1倍的處理能力)。
儲存裝置實時資訊方式
我儲存裝置相關資訊的方式是,每個裝置有乙個自己的統一的結構體,比如我最大支援
10000
個裝置,我就會先申請
1個指標陣列,大小為
10000
,占用40000b
,也就不到
40kb
記憶體。然後每新增乙個裝置,就給這個指標申請乙個記憶體,存放裝置的配置資訊,同時會使用託管的執行緒池非同步向資料庫中增加乙個裝置。
但是如果有幾千上萬個裝置的時候,尋找這個裝置的配置就變得很吃力了(相對來說,記憶體中遍歷都會比資料庫快),這個時候我就會對裝置進行分組,比如分
100組,最好的情況下每個組有
100個裝置,但是不排除有一種可能,乙個組中有超過
100個裝置的呀,我就要做乙個二維指標陣列,分
100個陣列,每個陣列中
1000
個裝置指標,這樣記憶體占用就會是
100*1000*4
,也還好
400k
,但是如果乙個組超過了
1000
個就不好辦了,同樣如果是
10w個裝置的時候,這個分組就很吃記憶體了,我的做法是每個分組用個變數進行記錄,每個組給
50個裝置指標,當這個組超過
50個之後,我重新對這個指標進行申請記憶體,大小為上一次的
+50個,然後把之前的資料拷貝過來,釋放掉之前的資料,這樣就可以動態的進行分組控制,實現效率的提公升與記憶體的最小消耗。
使用分組提高查詢的乙個例子
//查詢指定sn的裝置索引
//返回索引;-1:沒有找到
//2017-12-27 : 會使用分組進行快速查詢索引,只能在單執行緒中使用,不要跨執行緒搜尋
int findsn(char psn[16])
groupindex = temp[0] * 100 + temp[1] * 10 + temp[2];//計算當前裝置的分組索引
if (groupindex >= device_group_cnt) return -1; //分組索引無效
hash = user_lib.bkdrhash(psn); //計算雜湊結果
//在指定的分組內去搜尋當前裝置
for (dword i = 0; i < this->groupdevicecnt[groupindex]; i++)
}return -1;
}
新增裝置的例子,先新增到全域性的配置陣列中,然後再把指標儲存乙份到分組索引中
//新增乙個裝置到配置緩衝區,返回索引,<0:新增失敗
int adddevice(device_config_type *pconfig, char **perror)
if (this->devicecnt >= device_max_cnt) //裝置數量超出範圍
pconfig->sn[15] = 0;
if (strlen(pconfig->sn) != 15)
//檢查最後3位是否為000-999
temp[0] = pconfig->sn[12] - '0'; //字元轉換為數字
temp[1] = pconfig->sn[13] - '0'; //字元轉換為數字
temp[2] = pconfig->sn[14] - '0'; //字元轉換為數字
if (temp[0] > 9 || temp[1] > 9 || temp[2] > 9)
groupindex = temp[0] * 100 + temp[1] * 10 + temp[2]; //計算當前裝置的分組索引
if (groupindex >= device_group_cnt)
if (findsn(pconfig->sn) >= 0) //尋找指定位址的裝置是否存在
p = new one_device_data_type; //申請記憶體
memset(p, 0, sizeof(one_device_data_type)); //清控配置區域
memcpy(&p->config, pconfig, sizeof(device_config_type)); //拷貝資料
p->config.hash = user_lib.bkdrhash(p->config.sn); //生成sn的雜湊值
p->dbstatus.readhistcongifcnt = p->dbstatus.readhiststatuscnt = p->dbstatus.writehistcongifcnt = -1; //將歷史記錄條數置為-1無效值
p->index = this->devicecnt; //記錄當前裝置的索引
//將當前裝置編號進行分組
if (this->adddevicetogroup(groupindex, (dword)p) == false)
u32_devicedatapointerbuff[this->devicecnt] = (dword)p; //存放指標
pdevicedatapointerbuff[this->devicecnt++] = p; //儲存指標
return (this->devicecnt - 1); //返回當前的索引
}
新增裝置到分組中,如果分組滿了將會進行擴充
//新增乙個裝置到指定分組中,如果分組慢,將會申請擴容
//不會進行編號等檢查,只能在adddevice中被呼叫
bool adddevicetogroup(int groupindex, dword devicedatapointer)
sys_log.write("分組" + groupindex + "擴容成功\r\n");
} this->pdevicedatagrouppointerbuff[groupindex][this->groupdevicecnt[groupindex]] = devicedatapointer; //儲存當前裝置指標
this->groupdevicecnt[groupindex] ++; //分組內的裝置數量增加
return true;
}
//為指定的分組進行擴容,會先複製緩衝區,然後重新申請,再釋放之前的緩衝區(注意:使用分組索引只能在乙個執行緒中使用)
//必須分組已經滿了再呼叫
bool devicegroupexpansion(int groupindex)
後面我會擴充套件使用這個協議的下位機與服務端框架,並提供相應的測試例子。 分享乙個可以自定義日期格式的方法
相信大家在開發過程中,經常會需要用到各種的日期格式,如 2020 05 07 2020年5月7日 2020年5月7日 15 52 47 等等的日期格式要求,不知道大家都寫過多少遍的轉日期格式的方法了,反正天某是寫煩了,於是就產生了想要封裝乙個工具出來的想法。export class tools re...
乙個自定義訊息的例子
h define idm myclosepress 45571 lresult onmyclose wparam wparam,lparam lparam cpp begin message map cprogress,cdialog on wm close on message idm myclo...
自定義的乙個日曆Calender
產品要做簽到功能,簽到功能要基於乙個日曆來進行,所以就根據 要求自定義了乙個日曆 自定義控制項相信做android都知道 1 首先建立乙個類,繼承乙個容器類或者是乙個控制項 2 然後就是你需要設定的屬性等的,在attrs資料夾中 3 然後就是在類裡邊進行屬性的設定以及布局等等功能的新增 其實自定義乙...