[更新設計]跨平臺物聯網通信框架ServerSuperIO 2.0 ,功能、BUG、細節說明,以及升級思考過程!

     注:ServerSuperIO 2.0 尚未提交到開源社區,在內部測試!!!

1. ServerSuperIO(SSIO)說明

     SSIO是基於早期工業現場300波特率通信傳輸應用場景發展、演化而來。爲了適應互聯網、物聯網的發展趨勢,以及不一樣應用場景的需求,SSIO也在不斷的進行更新。html

     SSIO是一個跨平臺的物聯網通信框架,可是其本質不只僅是通信框架,而是設備驅動、串口和網絡IO管理器、場景控制器三者之間的協調與調度機制。git

物聯網是一個發展趨勢,若是各類傳感器、硬件設備的協議驅動沒法統一,那麼使用SSIO框架來開發設備驅動,隨意掛載到框架運行而且進行通信和交互,你擁有的是集成能力,以及對用戶的承諾;若是是公司內部使用,協議是「標準」的,那麼使用SSIO更簡單、方便,下降人員成本、提升生產效率。github

2. 升級概要

1.1  功能

1.在串口和網絡IO中增長接收數據緩存功能,充分利用緩存空間,保證數據的完整性。緩存

2.修改數據分發策略,如今以遠程IP或設備編號兩種方式分發數據。網絡

3.增長接收數據過濾器,保證數據按必定的規則進行提取,以及保證數據的連續性。併發

4.增長定時、超時清理網絡鏈接資源,若是網絡鏈接在必定時間範圍內沒有接到數據,則進行清理。框架

5.其餘代碼優化。異步

1.2 BUG

1.修復:退出軟件可能形成的異常。socket

2.修復:分發數據的邏輯問題。ide

1.3 細節

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. 升級考慮

3.1  設備/傳感器編碼

      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;
            }
 }

3.3  接收數據過濾器

    接收數據過濾器是按必定的原則在數據緩存中查找、提取數據信息,過濾器接口定義以下代碼:

/// <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),這幾種方式各有利弊,請根據不一樣設備的協議使用不一樣的過濾器。

3.4 定時檢測,超時清理網絡鏈接

      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);
                }
            }
}

3.5 數據分發原則

    對於輪詢模式通信,不存在數據分發,由於每次高度設備驅動,都是順序執行發送和接收操做,接收的數據確定是這個設備驅動的,就會當即返回。

    可是對於併發模式、自主模式、單例模式的通信方式(應用場景),是異步接收數據信息,我怎麼知道接收過來的數據應該分配哪一個設備驅動呢?有兩種方式:按IP和按設備編碼(原來是按數字類型的設備地址)。接收到的數據,會經過設備協議驅動與設備參數進行比對,而且進行數據分發。以下代碼:

/// <summary>
  /// 分發數據模式
  /// </summary>
    public enum DeliveryMode
    {
        [EnumDescription("設備IP分發數據")]
        DeviceIP,
        [EnumDescription("設備編碼分發數據")]
        DeviceCode
    }

 

相關文章
相關標籤/搜索