1.C#跨平台物聯網通訊框架ServerSuperIO(SSIO)介紹
《連載 | 物聯網框架ServerSuperIO教程》1.4種通訊模式機制。
《連載 | 物聯網框架ServerSuperIO教程》2.服務實例的配置參數說明
《連載 | 物聯網框架ServerSuperIO教程》- 3.設備驅動介紹
《連載 | 物聯網框架ServerSuperIO教程》-4.如開發一套設備驅動,同時支持串口和網絡通訊。
《連載 | 物聯網框架ServerSuperIO教程》- 5.輪詢通訊模式開發及注意事項。
《連載 | 物聯網框架ServerSuperIO教程》- 6.並發通訊模式開發及注意事項
《連載 | 物聯網框架ServerSuperIO教程》- 7.自控通訊模式開發及注意事項
《連載 | 物聯網框架ServerSuperIO教程》- 8.單例通訊模式開發及注意事項
目 錄
9. 協議過濾器,解決一包多發、粘包、冗余數據... 2
9.1 概述... 2
9.2 實際問題... 2
9.3 5種過濾器及二次開發... 5
9.4 設備驅動開發注意事項... 6
9.5 宿主程序服務實例配置注意事項... 6
通訊中涉及到數據包的概念,是通訊協議中的數據組成形式。針對這塊內容,說簡單也簡單,說復雜也復雜。需要我們系統性的把問題考慮全面,並用代碼實現。
在工業領域也有極端的情況出現,早些年做通訊的時候,數據包頭、包尾、數據長度、數據校驗位都對,但是就是解析出來的數據不正確,這種情況不會經常出現,但是在某種特殊應用環境可能會頻繁出現,後來經過分析得出結論:可能是由於地質電磁干擾引起的。但是也有技術上的設計缺陷,例如:數據校驗位是累加和,改成CRC是不是就不會出來這個問題了;另外對於增量數據,應該有補發機制等等。
參考協議:《連載 | 物聯網框架ServerSuperIO教程》-4.如開發一套設備驅動,同時支持串口和網絡通訊
多包發送數據是應用環境中的一種情況或一個問題,並不是我們會這樣實際應用,而是說在接收過程中多次接收數據才能完整接收客戶端一次發送的數據,可能由於網絡環境或發送數據端造成的,示意如下圖:
例如實時數據的完整包為:55 AA 00 61 43 7A 00 00 43 B4 15 0D。那麼接收數據的時候,第一次接收到:55 AA 00 61 43 7A 00 00 43 B4 15,第二次接到:0D。按通訊協議應該能夠把這兩次接收的數據進行自動拼接,形成完整的數據並進行解析。
ServerSuperIO設置了協議過濾器,可以解決這個問題,如下圖:
ServerSuperIO設置了協議過濾器,可以解決這個問題,如下圖:
FixedEndReceiveFliter:固定結尾的協議過濾器。 FixedHeadAndEndReceiveFliter:固定開頭和結尾的協議過濾器。 FixedHeadAndLengthReceiveFliter:固定開頭和長度的協議過濾器。 FixedHeadReceiveFliter:固定開頭的協議過濾器。 FixedLengthReceiveFliter:固定長度的協議過濾器。
這5個過濾器都繼承自IReceiveFilter接口,也可以繼承這個接口進行二次開發,定制自己的協議過濾器。代碼工程如下圖:
對於開發設備驅動,在初始化過程中可以增加這個驅動的協議過濾器,代碼如下:
public override void Initialize(string devid) { this.Protocol.InitDriver(this.GetType(),new FixedHeadAndEndReceiveFliter(new byte[] {0x55,0xaa},new byte[] {0x0d} )); …… }
在配置參數中需要配置:StartReceiveDataFliter = true,協議過濾器才能起到作用。代碼如下:
static void Main(string[] args) { DeviceSelfDriver dev2 = new DeviceSelfDriver(); dev2.DeviceParameter.DeviceName = "網絡設備"; dev2.DeviceParameter.DeviceAddr = 1; dev2.DeviceParameter.DeviceID = "1"; dev2.DeviceDynamic.DeviceID = "1"; dev2.DeviceParameter.DeviceCode = "1"; dev2.DeviceParameter.NET.RemoteIP = "127.0.0.1"; dev2.DeviceParameter.NET.RemotePort = 9600; dev2.CommunicateType = CommunicateType.NET; dev2.Initialize("1"); IServer server = new ServerManager().CreateServer(new ServerConfig() { ServerName = "服務1", ComReadTimeout = 1000, ComWriteTimeout = 1000, NetReceiveTimeout = 1000, NetSendTimeout = 1000, ControlMode = ControlMode.Self, SocketMode = SocketMode.Tcp, StartReceiveDataFliter = true, ClearSocketSession = false, StartCheckPackageLength = false, CheckSameSocketSession = false, DeliveryMode = DeliveryMode.DeviceIP, }); server.AddDeviceCompleted += server_AddDeviceCompleted; server.DeleteDeviceCompleted+=server_DeleteDeviceCompleted; server.Start(); server.AddDevice(dev2); while ("exit" == Console.ReadLine()) { server.Stop(); } }