1. ServerSuperIO(SSIO)說明
SSIO是基於早期工業現場300波特率通信傳輸應用場景發展、演化而來。爲了適應互聯網、物聯網的發展趨勢,以及不一樣應用場景的需求,SSIO也在不斷的進行更新。html
SSIO是一個跨平臺的物聯網通信框架,可是其本質不只僅是通信框架,而是設備驅動、串口和網絡IO管理器、場景控制器三者之間的協調與調度機制。git
物聯網是一個發展趨勢,若是各類傳感器、硬件設備的協議驅動沒法統一,那麼使用SSIO框架來開發設備驅動,隨意掛載到框架運行而且進行通信和交互,你擁有的是集成能力,以及對用戶的承諾;若是是公司內部使用,協議是「標準」的,那麼使用SSIO更簡單、方便,下降人員成本、提升生產效率。github
2. 升級概要
1.在串口和網絡IO中增長接收數據緩存功能,充分利用緩存空間,保證數據的完整性。緩存
2.修改數據分發策略,如今以遠程IP或設備編號兩種方式分發數據。網絡
3.增長接收數據過濾器,保證數據按必定的規則進行提取,以及保證數據的連續性。併發
4.增長定時、超時清理網絡鏈接資源,若是網絡鏈接在必定時間範圍內沒有接到數據,則進行清理。框架
5.其餘代碼優化。異步
1.修復:退出軟件可能形成的異常。socket
2.修復:分發數據的邏輯問題。ide
1.在協議驅動IProtocolDriver增長GetCode和GetPackageLength接口。GetCode通常爲設備的惟一編號;GetPackageLength通常得到本次數據包應該接收的數據長度,在框架中並未實際使用。
2.把CommandCache命令空間改成DataCache,下面增長ISendCache發送緩存接口和IReceiveCache接收緩存接口。
3.把如今設備驅動中的CommandCache改成SendCache發送數據緩存,移植到ProtocolDriver協議驅動中。
4.在ComSession和TcpSocketSession中增長ReceiveCache接收數據緩存。
5.增長IReceiveFilter接收數據過濾器接口。
7.去掉按設備地址分發數據,增長按設備編碼分發數據。
8.網絡偵聽鏈接的時候,退出軟件有可能形成異常。
9.網絡異步接收數據時,在邏輯上有可能形成分發錯誤。
10.對配置文件進行修改,增長StartReceiveDataFliter、ClearSocketSession、ClearSocketSessionInterval和ClearSocketSessionTimeOut。
11.網絡通信時,去掉多少次沒有接收到數據進行清理鏈接的功能。
3. 升級考慮
SSIO原來是用設備地址(DeviceAddress)來識別設備驅動,而DeviceAddress是int類型,不能知足業務場景的需求了,由於設備編碼不只僅是一個數字類型的數值,有多是一串字符串,包括數字和字母。設備編碼包括設備地址,是識別設備的一個規則編碼。有時候設備編碼與設備地址是等同的。
因此在設備驅動中增長了GetCode接口,這個接口也做爲網絡異步接收數據使用過濾器查找設備的接口,通常須要在配置文件設備StartReceiveDataFliter屬性。
GetCode能夠進行模糊查找,而且返回設備編碼,以下代碼:
public override string GetCode(byte[] data) { int codeIndex = -1; byte[] head=new byte[] {0x55,0xaa}; for (int i = 0; i < data.Length; i++) { if (data.Mark(0, data.Length, i, head)) { codeIndex = i; break; } } if (codeIndex == -1) { return String.Empty; } else { return data[codeIndex + head.Length].ToString("00#"); } }
3.2 接收數據緩存
SSIO之前接收完數據,直接從緩存中提取數據後返回給了設備驅動;也有另一種方案,就是建立一個更大的緩存對象保存byte數據,可是這種方案有些浪費內存空間,以及效率。
SSIO如今採用了折中方案,利用現有的緩存空間(byte[]),配合接收數據過濾器,對已經接收到的數據進行管理和過濾提取,而且對未提取的數據有持久存儲的能力。代碼以下:
/// <summary> /// 得到數據 /// </summary> /// <param name="filter"></param> public IList<byte[]> Get(IReceiveFilter filter) { if (filter == null) { throw new NullReferenceException("filter引用爲空"); } if (DataLength <= 0) { return new List<byte[]>(); } lock (_SyncLock) { int lastByteOffset = InitOffset; IList<byte[]> listBytes = filter.Filter(ReceiveBuffer, InitOffset, DataLength, ref lastByteOffset); if (listBytes != null && listBytes.Count > 0 && lastByteOffset>InitOffset) { CurrentOffset = lastByteOffset + 1; int gets = CurrentOffset - InitOffset ; DataLength -= gets; MoveLeft(gets); } return listBytes; } }
接收數據過濾器是按必定的原則在數據緩存中查找、提取數據信息,過濾器接口定義以下代碼:
/// <summary> /// 過濾數據信息 /// </summary> /// <param name="receiveBuffer">緩衝區</param> /// <param name="offset">偏移量</param> /// <param name="length">有效數據長度</param> /// <param name="lastByteOffset">最後一個字節的偏移量</param> /// <returns>沒有數據返回null</returns> IList<byte[]> Filter(byte[] receiveBuffer, int offset, int length, ref int lastByteOffset);
SSIO在此接口的基礎上,實現了5種數據過濾方式,固定結尾的方式(FixedEndReceiveFliter)、固定開頭和結尾的方式(FixedHeadAndEndReceiveFliter)、因定開頭的方式(FixedHeadReceiveFliter)、固定開頭和長度的方式(FixedHeadAndLengthReceiveFliter)、因定長度的方式(FixedLengthReceiveFliter),這幾種方式各有利弊,請根據不一樣設備的協議使用不一樣的過濾器。
SSIO之前是設置一個發送和接收次數值,若是超過這個值,尚未接收到數據信息,那麼就認爲是失效的IO通道,就會關閉、釋放掉資源。
SSIO如今增長了定時檢測功能,若是在必定時間範圍內(可設備)尚未接收到數據,那麼就認爲是失效的IO通道,就會關閉、釋放掉資源。代碼以下:
private void ClearSocketSession(object state) { if (Monitor.TryEnter(state)) { try { ICollection<IChannel> socketChannels = this.ChannelManager.GetChannels(CommunicateType.NET); if (socketChannels == null || socketChannels.Count<=0) return; DateTime now = DateTime.Now; IEnumerable<IChannel> timeoutSessions = socketChannels.Where(c => (now-((ISocketSession)c).LastActiveTime).Seconds>Config.ClearSocketSessionTimeOut); System.Threading.Tasks.Parallel.ForEach(timeoutSessions, c => { ISocketSession s = ((ISocketSession) c); Logger.Info(true,String.Format("網絡鏈接超時:{0}, 開始時間: {1}, 最後激活時間:{2}!", now.Subtract(s.LastActiveTime).TotalSeconds, s.StartTime, s.LastActiveTime)); RemoveTcpSocketSession(s); }); } catch (Exception ex) { this.Logger.Error(true,ex.Message); } finally { Monitor.Exit(state); } } }
對於輪詢模式通信,不存在數據分發,由於每次高度設備驅動,都是順序執行發送和接收操做,接收的數據確定是這個設備驅動的,就會當即返回。
可是對於併發模式、自主模式、單例模式的通信方式(應用場景),是異步接收數據信息,我怎麼知道接收過來的數據應該分配哪一個設備驅動呢?有兩種方式:按IP和按設備編碼(原來是按數字類型的設備地址)。接收到的數據,會經過設備協議驅動與設備參數進行比對,而且進行數據分發。以下代碼:
/// <summary> /// 分發數據模式 /// </summary> public enum DeliveryMode { [EnumDescription("設備IP分發數據")] DeviceIP, [EnumDescription("設備編碼分發數據")] DeviceCode }
2.[開源]C#跨平臺物聯網通信框架ServerSuperIO(SSIO)介紹
2.應用SuperIO(SIO)和開源跨平臺物聯網框架ServerSuperIO(SSIO)構建系統的總體方案
3.C#工業物聯網和集成系統解決方案的技術路線(數據源、數據採集、數據上傳與接收、ActiveMQ、Mongodb、WebApi、手機App)
5.ServerSuperIO開源地址:https://github.com/wxzz/ServerSuperIO
物聯網&集成技術(.NET) QQ羣:54256083