目 錄
第六章 通訊控制器的設計... 2
6.1 控制器接口... 2
6.2 串口控制器... 3
6.3 網絡控制器... 5
6.4 通訊控制管理器... 9
6.5 遠程交互... 9
6.6 小結... 10
經過前幾章的介紹,這章介紹通訊控制器。主要負責對設備驅動(IRunDevice)、IO通道(IIOChannel)進行協調、調度、以及事件做出響應,在此基礎上實現輪詢通訊模式、並發通訊模式和自控通訊模式的任務調度。由於串口和網絡硬件鏈路特性的原因以及通訊機制不一樣,所以通訊控制器的實現上也有很大差別。
控制器內置一個線程負責對設備驅動和IO實例進行任務協調、調度,相當於在《第4章 設備管理器的設計》、《第5章 串口和網絡的IO設計》實現的基礎上構建了一個更高層次的協調機制,並實現設備與IO的匹配、不同的通訊機制。
不管串口通訊控制器和網絡通訊控制器如何實現,都會繼承自統一的(IIOController)接口,接口定義的代碼如下:
public interface IIOController { /// <summary> /// 當然是否工作 /// </summary> bool IsWorked { set; get; } /// <summary> /// IO控制器的關鍵字。 /// </summary> string Key { get; } /// <summary> /// 啟動服務 /// </summary> void StartService(); /// <summary> /// 停止服務 /// </summary> void StopService(); /// <summary> /// IO控制器類型 /// </summary> CommunicationType ControllerType { get; } }
控制層次結構圖如下:
每個(硬件)串口都對應一個串口控制器,每個串口控制器裡都會有一個獨立的線程,也就是說用到多少個串口號就會有多少個控制器和線程。框架平台可能會掛載多個設備驅動(插件),有可能一個設備驅動對應一個串口,也可能幾個設備驅動共用一個串口,那麼也就是說串口控制器和設備驅動之間存在1對1或1對N的關系。結構示意圖如下:
某個設備調度周期=(串口控制器所有設備數-1)* 單個設備驅動執行耗時
這僅是一個理論值,實際應用中要比這個理論值要大,因為涉及到不類型的設備驅動共用一個串口號,在一個串口控制器下工作,處理的數據流程、方式不同,例如:有可能數據保存在TXT文件中、有可能保存在SQL數據庫中、有可能保存在NoSQL數據庫中等等。
有人會想,豈不是在一個串口下掛載的設備越多效率越低,的確是這樣的。但是,多個串口控制器之間是並行工作模式。如果現場環境對通訊效率有要求的話,可以增加串口服務器,也就是增加可用的串口硬件電路,把N個設備驅動平衡負載到不同的串口上,增加並行運行的串口控制器的節點,進而提高框架平台的運行效率。
但是,這樣解決之後也帶來一定的風險和瓶頸,就是對於數據的存儲,如果多個並行的數據流同時向一個單線程的存儲介質寫數據,那麼又會造成互斥的現象,甚至造成意想不到的結果或異常,如下圖:
如果同時向Sql Server、Oracle、Mysql等數據庫存儲數據,那麼是沒有問題的;如果采用文本文件、桌面數據庫等存儲數據,那麼可能存在問題,可以分多個文件進行保存操作。DCS系統大多采用PI(Plant Information System)數據庫。總之,作為一個系統來講,需要整體設計、考慮,這塊需要特別注意。
框架平台只有一個網絡控制器,網絡控制器內有一個獨立的線程負責對所有網絡設備驅動進行輪詢、並發、自控模式通訊調度。輪詢通訊模式與串口控制器類似,只是串行的調度所有網絡設備驅動,但是框架只有一個網絡控制器,不能通過增加網絡控制器來提高通訊效率,這種模式是網絡通訊調度雞肋;並發通訊模式,線程會通過控制器中的線程集中發送所有設備的請求命令數據,接收數據是通過IO異步監聽來完成,異步接收到數據後再把數據分發到設備驅動的RunIODevice接口,進行數據處理;自控通訊模式,發送命令數據的職能移交給了設備驅動本身,可以通過定時器來完成發送命令數據的功能,線程不再負責發送命令數據,接收數據與並發通訊模式一樣。網絡控制器的內部示意圖如下:
public void ControllerSend(IRunDevice dev, byte[] data) { int counter = DeviceManager.GetInstance().GetCounter(dev.DeviceParameter.DeviceID.ToString()); int sendNum = SessionSocketManager.GetInstance().Send(dev.DeviceParameter.NET.RemoteIP, data); if (sendNum == data.Length && sendNum != 0) { DeviceMonitorLog.WriteLog(dev.DeviceParameter.DeviceName, "發送請求數據"); Interlocked.Increment(ref counter); } else { Interlocked.Increment(ref counter); DeviceMonitorLog.WriteLog(dev.DeviceParameter.DeviceName, "嘗試發送數據失敗"); } dev.ShowMonitorIOData(data, "發送"); if (counter >= 3) { try { dev.RunIODevice(new byte[] { }); } catch (Exception ex) { DeviceMonitorLog.WriteLog(dev.DeviceParameter.DeviceName, ex.Message); GeneralLog.WriteLog(ex); } Interlocked.Exchange(ref counter, 0); } DeviceManager.GetInstance().SetCounter(dev.DeviceParameter.DeviceID.ToString(), counter); }
異步接收、分數據的代碼如下:
private void NETDeviceController_ReceiveSocketData(object source, ReceiveSocketDataArgs e) { if (GlobalProperty.GetInstance().ControlMode == ControlMode.Parallel || GlobalProperty.GetInstance().ControlMode == ControlMode.Self) { int counter = 0; IRunDevice dev = null; IRunDevice[] list = DeviceManager.GetInstance().GetDevices(e.RemoteIP, CommunicationType.NET); for (int i = 0; i < list.Length; i++) { dev = list[i]; if (String.CompareOrdinal(dev.DeviceParameter.NET.RemoteIP, e.RemoteIP) == 0) { dev.ShowMonitorIOData(e.ReceiveData, "接收"); dev.AsyncRunIODevice(e.ReceiveData); counter = DeviceManager.GetInstance().GetCounter(dev.DeviceParameter.DeviceID.ToString()); Interlocked.Decrement(ref counter); if (counter < 0) { Interlocked.Exchange(ref counter, 0); } DeviceManager.GetInstance().SetCounter(dev.DeviceParameter.DeviceID.ToString(), counter); } } } }
通訊控制管理器負責對串口控制器和網絡控制器進行管理,實際上是對Dictionary<Key,Value>進行的封裝,所有涉及到操作控制器的地方都是通過控制管理器來完成的。IIOControllerManager<TKey, TValue>通訊控制管理器的接口定義如下:
在了解串口控制器和網絡控制器的基本原理和功能後,還要考慮到一個應用場景:控制器不僅僅要與硬件進行數據交互,還有可能要把采集上來的數據轉發到其他服務器或節點上,也就是框架平台要具備路由的功能,整合設備驅動采集上來的數據,進行打包、轉發。
從這個應用場景來看,在開發設備驅動的時候,不適合在設備驅動的處理流程中進行轉發、多業務處理,受環境、網絡、業務復雜度的影響可能會阻塞控制器的調度,影響框架的整體運行效率。
在物聯網建設中,多級互聯、逐層轉發是很常見技術需求。為了解決這個現實問題,框架平台提供了IAppService應用服務接口,二次開發者可以把設備驅動中的數據信息封裝後傳入到IAppService接口中,可以在這裡實現緩存、轉發等具體的業務服務。這樣設計的主要目的是不影響框架平台實時的數據采集,保證數據源的穩定性。
IAppService具體的設計和應用將來《第7章 外部接口的設計》中進行詳細介紹。
通訊控制器實現這後,理論上框架平台就能夠跑起來了,但是距離我們開始設計的目標還差很多工作要做,還不能為二次開發提供很大的便利。在後續的設計中,慢慢的會把框架平台豐富起來。
作者:唯笑志在
Email:[email protected]
QQ:504547114
.NET開發技術聯盟:54256083
文檔下載:http://pan.baidu.com/s/1pJ7lZWf
官方網址:http://www.bmpj.net