SuperSocket 提供了一些通用的協議解析工具, 你能夠用他們簡單並且快速的實現你本身的通訊協議:session
因爲本次項目涉及的通訊協議是頭部格式固定而且包含內容長度的協議這裏主要講解使用FixedHeaderReceiveFilter來拆解.ide
通訊協議格式以下:工具
代碼 | 字節數 | 說明 |
68H | 1 | 幀起始碼 |
DLC | 4 | 設備邏輯地址 |
SEQ | 2 | 主站地址與命令序號 |
68H | 1 | 幀起始碼 |
C | 1 | 控制碼 |
L | 2 | 數據長度(DATA長度) |
DATA | 變長 | 數據內容 |
CS | 1 | 校驗碼 |
16H | 1 | 結束碼 |
在FixedHeaderReceiveFilter,頭部指數據內容以前的數據(即數據長度L以前的部分),以上協議能夠知道,頭部包含11個字節.測試
首先,根據協議的須要來定義本身的請求類型,先實現一個客戶端請求的實體類RequestInfo,改RequestInfo類必須實現接口 IRequestInfo,該接口只有一個名爲"Key"的字符串類型的屬性.SuperSocket設計了兩個RequestInfo類:StringRequestInfo 和BinaryRequestInfo,這裏咱們自定義一個來GDProtocolRequestInfo實現:spa
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; }
} }
而後設計基於類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; } } }
先建立新的AppSession,GDProtocolSessionV2,新的AppServer將使用GDProtocolSessionV2.GDProtocolSessionV2代碼以下:調試
using SuperSocket.SocketBase; using SuperSocket.SocketBase.Protocol; using System; namespace GDServer { public class GDProtocolSessionV2 : AppSession<GDProtocolSessionV2, GDProtocolRequestInfo> { protected override void HandleException(Exception e) { } } }
使用該協議的方法是使用接收或者本身定義的接收過濾器工廠來在 SuperSocket 中啓用該協議code
using SuperSocket.SocketBase; using SuperSocket.SocketBase.Protocol; namespace GDServer { public class GDProtocolServerV2 : AppServer<GDProtocolSessionV2, GDProtocolRequestInfo> { public GDProtocolServerV2() : base(new DefaultReceiveFilterFactory<GDProtocolReceiveFilterV2, GDProtocolRequestInfo>()) //使用默認的接受過濾器工廠 (DefaultReceiveFilterFactory)
{ } } }
這樣,GDProtocolServerV2就完成了,下面是測試代碼:server
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方式發送)blog
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/原創,轉載請著名出處