- 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)---头部格式固定并包含内容长度协议
1、TerminatorReceiveFilter结束符协议
结束符协议和命令行协议类似,一些协议用结束符来确定一个请求.例如, 一个协议使用两个字符 "##" 作为结束符, 于是你可以使用类 "TerminatorReceiveFilterFactory":
结束符协议TerminatorProtocolServer
:
public class TerminatorProtocolServer : AppServer
{
public TerminatorProtocolServer()
: base(new TerminatorReceiveFilterFactory("##"))
{
}
}
基于TerminatorReceiveFilter实现你的接收过滤器(ReceiveFilter):
public class YourReceiveFilter : TerminatorReceiveFilter<YourRequestInfo>
{
//More code
}
实现你的接收过滤器工厂(ReceiveFilterFactory)用于创建接受过滤器实例:
public class YourReceiveFilterFactory : IReceiveFilterFactory<YourRequestInfo>
{
//More code
}
2、CountSpliterReceiveFilter 固定数量分隔符协议
有些协议定义了像这样格式的请求 "#part1#part2#part3#part4#part5#part6#part7#". 每个请求有7个由 '#' 分隔的部分. 这种协议的实现非常简单:
/// <summary>
/// 请求格式:#part1#part2#part3#part4#part5#part6#part7#
/// </summary>
public class CountSpliterAppServer : AppServer
{
public CountSpliterAppServer()
: base(new CountSpliterReceiveFilterFactory((byte)'#', 8)) //8个分隔符,7个参数。除使用默认的过滤工厂,还可以参照上一个实例定制协议
{
}
}
3、FixedSizeReceiveFilter 固定请求大小协议
在这种协议之中, 所有请求的大小都是相同的。如果你的每个请求都是有8个字符组成的字符串,如"HUANG LI", 你应该做的事就是想如下代码这样实现一个接收过滤器(ReceiveFilter):
class MyReceiveFilter : FixedSizeReceiveFilter<StringRequestInfo>
{
public MyReceiveFilter()
: base(8) //传入固定的请求大小
{
}
protected override StringRequestInfo ProcessMatchedRequest(byte[] buffer, int offset, int length, bool toBeCopied)
{
//TODO: 通过解析到的数据来构造请求实例,并返回
}
}
然后在你的 AppServer 类中使用这个接受过滤器 (ReceiveFilter):
public class MyAppServer : AppServer
{
public MyAppServer()
: base(new DefaultReceiveFilterFactory<MyReceiveFilter, StringRequestInfo>()) //使用默认的接受过滤器工厂 (DefaultReceiveFilterFactory)
{
}
}
4、BeginEndMarkReceiveFilter 带起止符协议
在这类协议的每个请求之中 都有固定的开始和结束标记。例如, 我有个协议,它的所有消息都遵循这种格式 "&xxxxxxxxxxxxxx#"。因此,在这种情况下, "&" 是开始标记, "#" 是结束标记,于是你的接受过滤器可以定义成这样:
class MyReceiveFilter : BeginEndMarkReceiveFilter<StringRequestInfo>
{
//开始和结束标记也可以是两个或两个以上的字节
private readonly static byte[] BeginMark = new byte[] { (byte)'&' };
private readonly static byte[] EndMark = new byte[] { (byte)'#' };
public MyReceiveFilter()
: base(BeginMark, EndMark) //传入开始标记和结束标记
{
}
protected override StringRequestInfo ProcessMatchedRequest(byte[] readBuffer, int offset, int length)
{
//TODO: 通过解析到的数据来构造请求实例,并返回
}
}
然后在你的 AppServer 类中使用这个接受过滤器 (ReceiveFilter):
public class MyAppServer : AppServer
{
public MyAppServer()
: base(new DefaultReceiveFilterFactory<MyReceiveFilter, StringRequestInfo>()) //使用默认的接受过滤器工厂 (DefaultReceiveFilterFactory)
{
}
}
5、FixedHeaderReceiveFilter 头部格式固定并包含内容长度协议
这种协议将一个请求定义为两大部分, 第一部分定义了包含第二部分长度等等基础信息. 我们通常称第一部分为头部.
例如, 我们有一个这样的协议: 头部包含 6 个字节, 前 4 个字节用于存储请求的名字, 后两个字节用于代表请求体的长度:
/// +-------+---+-------------------------------+
/// |request| l | |
/// | name | e | request body |
/// | (4) | n | |
/// | |(2)| |
/// +-------+---+-------------------------------+
使用 SuperSocket, 你可以非常方便的实现这种协议:
class MyReceiveFilter : FixedHeaderReceiveFilter<BinaryRequestInfo>
{
public MyReceiveFilter()
: base(6)
{
}
protected override int GetBodyLengthFromHeader(byte[] header, int offset, int length)
{
return (int)header[offset + 4] * 256 + (int)header[offset + 5];
}
protected override BinaryRequestInfo ResolveRequestInfo(ArraySegment<byte> header, byte[] bodyBuffer, int offset, int length)
{
return new BinaryRequestInfo(Encoding.UTF8.GetString(header.Array, header.Offset, 4), bodyBuffer.CloneRange(offset, length));
}
}
你需要基于类FixedHeaderReceiveFilter实现你自己的接收过滤器.
-
- 传入父类构造函数的 6 表示头部的长度;
- 方法"GetBodyLengthFromHeader(...)" 应该根据接收到的头部返回请求体的长度;
- 方法 ResolveRequestInfo(....)" 应该根据你接收到的请求头部和请求体返回你的请求类型的实例.
实际使用场景:
到这里五种协议的模板你都已经了解了一遍,并且知道了相关的格式处理。接下来看一个网络示例:
通讯协议格式:
在看到上图协议是在纠结客户端发送16进制,服务器怎么接收,16进制的报文如下:
26 01 00 19 4E 4A 30 31 31 01 44 41 31 31 32 00 07 00 00 00 00 00 00 34 23
16进制也好,10进制也好,其他的进制也好,最终都是转换成byte[],其实在处理数据时,发送过去的数据都是可以转换成为byte[]的,所以服务的只要解析byte[]数组就行了。按照协议来解析就能得到想要的数据。下面使用FixedSizeReceiveFilter的例子,代码如下:
根据上面的通讯协议,开始来实现解析:
第一步、定义一个和协议合适的数据结构
第二步、建立一个RequestInfo来给server数据接收
第三步、FixedSize协议解析
第四步、建立协议工厂HLReceiveFilterFactory
第五步、自定义HLProtocolSession继承AppSession
第六步、自定义HLProtocolServer继承AppServer
第七步、加上起止符协议HLBeginEndMarkReceiveFilter
第八步、服务启动和停止
通讯协议需要使用小工具进行调试,本人使用的是TCP/UDP端口调试工具SocketTool V2.大家可以直接进行下载。使用HEX模式进行发送16进制报文,服务器输出结果:
本文参考官方文档 内置的常用协议实现模版