一、總體介紹
SuperSocket 是一個輕量級的可擴展的 Socket 開發框架,由江振宇先生開發。
官方網站:http://www.supersocket.net/
1、SuperSocket具有如下特點:
-
簡單易用,只需要幾個類就能創建出健壯的Socket服務器端程序
-
性能優良, 穩定可靠
-
支持各種協議, 內置的協議解析工具讓你把實現通信協議這種復雜的工作變得很簡單
-
自動支持SSL/TLS傳輸層加密
-
強大,靈活而且可擴展的配置讓你開發Socket服務器省時省力
-
支持多個socket服務器實例運行, 而且支持多個服務器實例的隔離
-
SuperSocket能以控制台或者Windows服務形式運行。一個腳本就能將SuperSocket安裝成服務
-
靈活的日志策略能夠記錄大部分socket活動
-
支持UDP
-
支持IPv6
-
支持Windows Azure
-
支持Linux/Unix操作系統(通過Mono 2.10或以上版本)
-
內置可直接使用的Flash/Silverlight Socket策略服務器
2、SuperSocket應對項目需求特點:
-
開源,基於Apache 2.0協議,可以免費使用到商業項目.
-
高性能的事件驅動通信.
-
會話級別的發送隊列能夠讓你通過會話並發的發送數據,並保持高性能和可控性.
-
強大且高性能的協議解析實現工具幫你簡化了網絡數據的分析工作.
-
輕量級意味着組件可以自由選擇使用,可根據環境變化變更.
3、SuperSocket的架構和設計
可以在官方的中文文檔查詢到http://docs.supersocket.net/v1-6/zh-CN/Architecture-Diagrams
- 每個連接的客戶端都以Session的方式管理,發送數據給客戶端也通過Session的Send方法,
- 每個客戶端發過來的數據流都經過ReceiveFilter過濾器(這里即可自定義協議或者使用自帶的一些幀過濾器)到ReqestInfo。
- ReqestInfo包含了該條數據內容,當然如果是自定義的協議,可以實現自己的ReqestInfo,把數據包內容直接裝入幀對象。
SuperSocket 層次示意圖
SuperSocket層次解析:
- 設備層:基於flash和SilverLight的策略服務器和基於接收過濾器的協議實施。
- 應用層:可擴展的應用程序服務:包括多種API集成。會話容器和命令框架。
- 套接字層: 通過傳輸協議TCP和UDP的事件驅動套接字服務。
SuperSocket 請求處理模型示意圖
模型解析:
- 客戶端攜帶數據流與Server端Socket Listener建立連接之后,SuperSocket 服務就將這一個連接視為一個Session會話。表示客戶端和服務器端的一個邏輯連接,數據的收發都是在這個Session中進行處理的(此過程中的數據流為二進制數據)。
- 攜帶數據流的Session通過默認或者自定的接受過濾器將過濾后的數據傳遞到RequestInfo對象。每一個客戶端對象都得實例化一個RequestInfo類,將接收到的二進制流轉換成請求的實例。
- 根據RequestInfo執行Command命令,一個Command 包含一個Session和RequestInfo,在Command中根據需求解析數據。也可通過Session向客戶端發送數據,例如有些DTU或者RTU設備需要發送指令才能返回數據。
SuperSocket 對象模型圖示意圖
模型解析:
- 應用服務AppServer 包括命令Commands, 會話容器Session contaioner。
- 對象層次:基本配置Config->命令過濾器Command Filters->日志和日志工廠Log/LogFactory->命令裝載機CommandLoaders->接收過濾器工廠ReceiveFilterFactory->連接過濾Connection Filters。
- Socket 服務:多客戶端監聽,TCP1 、TCP2、。。。。UDP。
4、SuperSocket內置的常用協議實現模版
為了減少碼農的工作量,SuperSocket內置的常用協議實現模版如下:
- TerminatorReceiveFilter ,結束符協議(SuperSocket.SocketBase.Protocol.TerminatorReceiveFilter, SuperSocket.SocketBase)
- CountSpliterReceiveFilter ,固定數量分隔符協議(SuperSocket.Facility.Protocol.CountSpliterReceiveFilter, SuperSocket.Facility)
- FixedSizeReceiveFilter, 固定請求大小的協議 (SuperSocket.Facility.Protocol.FixedSizeReceiveFilter, SuperSocket.Facility)
- BeginEndMarkReceiveFilter,帶起止符的協議 (SuperSocket.Facility.Protocol.BeginEndMarkReceiveFilter, SuperSocket.Facility)
- FixedHeaderReceiveFilter ,頭部格式固定並且包含內容長度的協議(SuperSocket.Facility.Protocol.FixedHeaderReceiveFilter, SuperSocket.Facility)
以上模板的使用可參考官方文檔http://docs.supersocket.net/v1-6/zh-CN/The-Built-in-Common-Format-Protocol-Implementation-Templates
5、通過請求處理模型可以總結基本的開發流程
- 實例化AppServer對象,時刻監聽客戶端的會話。
- 定義RequestInfo實體類型,接收和處理二進制字符流。
- 定義數據接收過濾器,ReceiveFilter,接收過濾后的數據,並將數據賦值給RequestInfo實體類型。
- 在appServer的構造函數中繼承使用接收過濾工廠RequestFilterFactory,並執行自定的ReceiveFilter和RequestInfo。
- 在1的數據請求委托事件中解析並使用RequestInfo實體中對應的數據。
二、通過FixedHeaderReceiveFilter解析自定義協議
自定義自己服務器中相關的類,建議類的建立順序:RequestInfo>ReceiveFilter>AppSession>AppServer
通信協議格式如下:
在FixedHeaderReceiveFilter,頭部指數據內容之前的數據(即數據長度L之前的部分),以上協議可以知道,頭部包含11個字節.
1、自定義請求類型RequestInfo
先實現一個客戶端請求的實體類RequestInfo,該RequestInfo類必須實現接口 IRequestInfo,該接口只有一個名為"Key"的字符串類型的屬性。
SuperSocket設計了兩個RequestInfo類:StringRequestInfo 和BinaryRequestInfo,這里我們自定義一個來GDProtocolRequestInfo實現:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using SuperSocket.SocketBase.Protocol; namespace GDServer { public class GDProtocolRequestInfo : IRequestInfo { /// <summary> /// [不使用] /// </summary> public string Key { get; set; } /// <summary> /// 設備邏輯地址 /// </summary> public string DeviceLogicalCode { get; set; } /// <summary> /// 命令序列號 /// </summary> public string Seq { get; set; } /// <summary> /// 控制碼 /// </summary> public string ControlCode { get; set; } /// <summary> /// 數據長度 /// </summary> public string Length { get; set; } /// <summary> /// 數據域 /// </summary> public string Data { get; set; } /// <summary> /// CS校驗 /// </summary> public string Cs { get; set; } /// <summary> /// 當前完整幀 /// </summary> //public string EntireFrame { get; set; } } }
2、自定義接收過濾器ReceiveFilter
設計基於類FixedHeaderReceiveFilter實現自己的接收過濾器GDProtocolReceiveFilterV2,主要實現GetBodyLengthFromHeader和ResolveRequestInfo方法,實現如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using SuperSocket.SocketBase.Protocol; using SuperSocket.Facility.Protocol;// using SuperSocket.Common;// namespace GDServer { /// <summary> /// 廣東規約過濾器V2,(幀格式為GDProtocolRequestInfo) /// </summary> public class GDProtocolReceiveFilterV2 : FixedHeaderReceiveFilter<GDProtocolRequestInfo> { public GDProtocolReceiveFilterV2() : base(11) { } /// <summary> /// 獲取數據域和結尾字節長度 /// </summary> /// <param name="header"></param> /// <param name="offset"></param> /// <param name="length"></param> /// <returns></returns> protected override int GetBodyLengthFromHeader(byte[] header, int offset, int length) { //length為頭部(包含兩字節的length)長度 //獲取高位 byte high = header[offset + length - 1]; //獲取低位 byte low = header[offset + length - 2]; int len = (int)high * 256 + low; return len + 2;//結尾有2個字節 } /// <summary> /// 實現幀內容解析 /// </summary> /// <param name="header"></param> /// <param name="bodyBuffer"></param> /// <param name="offset"></param> /// <param name="length"></param> /// <returns></returns> protected override GDProtocolRequestInfo ResolveRequestInfo(ArraySegment<byte> header, byte[] bodyBuffer, int offset, int length) { GDProtocolRequestInfo res = new GDProtocolRequestInfo(); string entireFrame = BytesToHexStr(header.Array) + BytesToHexStr(bodyBuffer.CloneRange(offset, length)); //res.EntireFrame = entireFrame; res.DeviceLogicalCode = entireFrame.Substring(2, 8); res.Seq = entireFrame.Substring(10, 4); res.ControlCode = entireFrame.Substring(16, 2); res.Length = entireFrame.Substring(18, 4); int dataLen = int.Parse(HEXtoDEC(ReverseHexString(res.Length))); res.Data = entireFrame.Substring(22, dataLen * 2); res.Cs = entireFrame.Substring(22 + dataLen * 2, 2); return res; } /// <summary> /// 高低對調 /// </summary> /// <param name="str"></param> /// <returns></returns> string ReverseHexString(string str) { char[] buff = new char[str.Length]; for (int i = 0; i < str.Length; i += 2) { buff[i] = str[str.Length - i - 2]; buff[i + 1] = str[str.Length - 1 - i]; } string s = new string(buff); return s; } /// <summary> /// 16進制轉10進制 /// </summary> /// <param name="HEX"></param> /// <returns></returns> string HEXtoDEC(string HEX) { return Convert.ToInt64(HEX, 16).ToString(); } /// <summary> /// 轉化bytes成16進制的字符 /// </summary> /// <param name="bytes"></param> /// <returns></returns> string BytesToHexStr(byte[] bytes) { string returnStr = ""; if (bytes != null) { for (int i = 0; i < bytes.Length; i++) { returnStr += bytes[i].ToString("X2"); } } return returnStr; } } }
3、自定義的AppSession
先創建新的AppSession,GDProtocolSessionV2,新的AppServer將使用它。
using SuperSocket.SocketBase; using SuperSocket.SocketBase.Protocol; using System; namespace GDServer { public class GDProtocolSessionV2 : AppSession<GDProtocolSessionV2, GDProtocolRequestInfo> { protected override void HandleException(Exception e) { } } }
4、自定義AppServer
使用該協議的方法是使用接收或者自己定義的接收過濾器工廠來在 SuperSocket 中啟用該協議
using SuperSocket.SocketBase; using SuperSocket.SocketBase.Protocol; namespace GDServer { public class GDProtocolServerV2 : AppServer<GDProtocolSessionV2, GDProtocolRequestInfo> { public GDProtocolServerV2() : base(new DefaultReceiveFilterFactory<GDProtocolReceiveFilterV2, GDProtocolRequestInfo>()) //使用默認的接受過濾器工廠 (DefaultReceiveFilterFactory) { } } }
5、測試程序
這樣,GDProtocolServerV2就完成了,下面是測試代碼:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using GDServer; namespace Test { class Program { static void Main(string[] args) { Console.ForegroundColor = ConsoleColor.Red; var gdServer = new GDProtocolServerV2(); gdServer.Setup(2015); gdServer.NewSessionConnected += gdServer_NewSessionConnected; gdServer.NewRequestReceived += gdServer_NewRequestReceived; gdServer.SessionClosed += gdServer_SessionClosed; gdServer.Start(); Console.WriteLine("server is:" + gdServer.State.ToString()); while (true) { if (Console.ReadKey().KeyChar == 'q') { gdServer.Stop(); gdServer.Dispose(); return; } } } static void gdServer_SessionClosed(GDProtocolSessionV2 session, SuperSocket.SocketBase.CloseReason value) { Console.WriteLine(session.RemoteEndPoint.ToString() + " closed. reason:" + value); } static void gdServer_NewRequestReceived(GDProtocolSessionV2 session, GDProtocolRequestInfo requestInfo) { var info = requestInfo; Console.WriteLine("receive from: " + session.RemoteEndPoint.ToString()); Console.WriteLine("DeviceLogicalCode:" + info.DeviceLogicalCode); Console.WriteLine("Seq:" + info.Seq); Console.WriteLine("ControlCode:" + info.ControlCode); Console.WriteLine("Length:" + info.Length); Console.WriteLine("Data:" + info.Data); Console.WriteLine("Cs:" + info.Cs); Console.WriteLine("-------------------------------------------------------------"); } static void gdServer_NewSessionConnected(GDProtocolSessionV2 session) { Console.WriteLine(session.RemoteEndPoint.ToString() + " connected."); } } }
測試結果:
分別發送符合該協議格式的幀(用TCP調試助手使用hex方式發送)
68 77 77 12 34 00 01 68 A1 03 00 11 11 11 DC 16
68 77 77 12 34 41 01 68 01 0C 00 01 00 00 00 00 00 00 00 30 80 10 80 94 16
68 77 77 12 34 41 01 68 88 08 00 00 00 30 80 00 10 80 00 16 16
68 77 77 12 34 41 01 68 95 23 00 00 0B 00 00 10 00 00 00 00 00 FF FF FF FF FF FF FF FF 00 00 5B 00 00 00 00 00 00 00 00 00 00 00 00 00 32 9E 16
打印結果如下:
server is:Running
127.0.0.1:34360 connected.
receive from: 127.0.0.1:34360
DeviceLogicalCode:77771234
Seq:0001
ControlCode:A1
Length:0300
Data:111111
Cs:DC
-------------------------------------------------------------
receive from: 127.0.0.1:34360
DeviceLogicalCode:77771234
Seq:4101
ControlCode:01
Length:0C00
Data:010000000000000030801080
Cs:94
-------------------------------------------------------------
receive from: 127.0.0.1:34360
DeviceLogicalCode:77771234
Seq:4101
ControlCode:88
Length:0800
Data:0000308000108000
Cs:16
-------------------------------------------------------------
receive from: 127.0.0.1:34360
DeviceLogicalCode:77771234
Seq:4101
ControlCode:95
Length:2300
Data:000B0000100000000000FFFFFFFFFFFFFFFF00005B0000000000000000000000000032
Cs:9E
-------------------------------------------------------------以上代碼請自行引入SuperSocket的dll和System.configuration.dll
本文由http://www.cnblogs.com/xiepeixing/原創,轉載請著名出處
三 、SuperSocket 1.6 中文文檔
http://docs.supersocket.net/v1-6/zh-CN
四、入門教程
https://www.cnblogs.com/fly-bird/category/938912.html