SuperSocket 1.5 Documentation译文 6 ----- 使用IRequestInfo,IRequestFilter等实现你自己的通信协议
你为什么要使用自己的通讯协议?
通信协议用于转换接收到的二进制数据为你的应用程序可以理解的数据。SuperSocket提供了一个内置的通信协议“命令行协议”,它定义了每个请求都必须一个回车符“\ r\ n”结束。
但是,一些应用程序不能使用“命令行协议”的原因有很多。在这种情况下,你需要使用下面的工具实现自己的通信协议:
* RequestInfo * ReceiveFilter * ReceiveFilterFactory * AppServer and AppSession
RequestInfo
RequestInfo是从客户端请求的实体类. 每个客户端的请求将会以RequestInfo被实例化. 该RequestInfo类必须实现接口IRequestInfo,在字符串类型的属性中只能有一个名为“key”:
public interface IRequestInfo { string Key { get; } }
谈到以前的文档中, 字符串类信息请求中RequestInfo的是使用的SuperSocket命令行协议。
您还可以实现自己的RequestInfo的类作为你的应用要求。例如,如果所有的请求都必须有一个 DeviceId 字段,你可以在RequestInfo类定义一个属性:
public class MyRequestInfo : IRequestInfo { public string Key { get; set; } public int DeviceId { get; set; } /* // 其他属性 */ }
SuperSocket也提供了另一个请求信息类“BinaryRequestInfo”用于二进制协议:
public class BinaryRequestInfo { public string Key { get; } public byte[] Body { get; } }
如果能满足你的要求,你可以直接使用BinaryRequestInfo。
ReceiveFilter
ReceiveFilter用于将接收到的二进制数据转换为您的请求信息实例。
为了实现一个ReceiveFilter,你需要实现该接口IReceiveFilter:
public interface IReceiveFilter<TRequestInfo> where TRequestInfo : IRequestInfo { /// <summary> /// 过滤器接收到的数据的特定会话的请求信息 /// </summary> /// <param name="readBuffer">读取缓冲器。</param> /// <param name="offset">这个读缓冲区中当前接收到的数据的偏移量.</param> /// <param name="length">当前接收到的数据的长度.</param> /// <param name="toBeCopied">如果设置为true则[复制].</param> /// <param name="rest">其余没有被解析部分的数据长度.</param> /// <returns></returns> TRequestInfo Filter(byte[] readBuffer, int offset, int length, bool toBeCopied, out int rest); /// <summary> /// 获取左边的缓冲区的大小. /// </summary> /// <value> /// 左边的缓冲区的大小. /// </value> int LeftBufferSize { get; } /// <summary> /// 获取下一个接收过滤器. /// </summary> IReceiveFilter<TRequestInfo> NextReceiveFilter { get; } /// <summary> /// 复位这个实例到初始状态. /// </summary> void Reset(); }
-
TRequestInfo:你要在应用中使用的请求信息类的参数类型是“TRequestInfo”
-
LeftBufferSize: 在请求过滤器中数据缓存的大小;
-
NextReceiveFilter: 下一块二进制数据被接收时将使用的请求过滤器;
-
Reset(): 复位这个实例到初始状态;
-
Filter(....): 通过SuperSocket在接收下一次二进制数据时这个过滤器方法将执行, 所接收的数据位于参数readBuffer. 因为readBuffer的所有连接共享相同的应用程序服务器实例, 因此,你需要加载的位置接收到的数据从“offset”(方法参数)和“length”(方法参数)的大小。
TRequestInfo Filter(byte[] readBuffer, int offset, int length, bool toBeCopied, out int rest);
- readBuffer:接收缓冲存储器,将接收到的数据被存储在这个数组
- offset: 接收到的数据的开始位置的readBuffer
- length: 所接收的数据的长度
- toBeCopied: 是否应该创建一个副本的readBuffer,而不是直接使用它的时候,我们要缓存中的数据表示
- rest: 这是一个输出参数,你找到一个完整的请求后它应该被设置为剩余的接收到的数据大小
有很多情况下,你需要处理:
- 如果你发现一个完整的请求从接收到的数据,你必须返回一个请求信息实例的请求信息类型.
- 如果你还没有找到一个完整的请求,你只需要返回NULL.
- 如果您有找到一个完整的从所接收的数据的请求,但接收到的数据不只包含一个请求, 设置剩余数据大小给输出参数"left". SuperSocket将会检查输出参数“rest”, 如果它大于0,通过调整参数“offset”和“length”过滤器方法将被再次执行.
The ReceiveFilterFactory
ReceiveFilterFactory是用于为每个会话创建接收过滤器。要定义您接收过滤器工厂类,则必须实现接口IReceiveFilterFactory。参数类型“TRequestInfo”是你在应用中使用的请求信息类
/// <summary> /// 接收过滤器工厂接口 /// </summary> /// <typeparam name="TRequestInfo">请求信息的类型.</typeparam> public interface IReceiveFilterFactory<TRequestInfo> : IReceiveFilterFactory where TRequestInfo : IRequestInfo { /// <summary> /// 创建接收过滤器. /// </summary> /// <param name="appServer">应用服务器.</param> /// <param name="appSession">该应用程序会话.</param> /// <param name="remoteEndPoint">远程端点.</param> /// <returns> /// 新创建的与此套接字会话相关的请求过滤器 /// </returns> IReceiveFilter<TRequestInfo> CreateFilter(IAppServer appServer, IAppSession appSession, IPEndPoint remoteEndPoint); }
您也可以使用默认的接收过滤器厂
DefaultReceiveFilterFactory<TReceiveFilter, TRequestInfo>
当方法CreateFilter被调用时,它会返回无参构造函数类TReceiveFilter的实例。
通过AppSession和AppServer工作
现在,你有RequestInfo,ReceiveFilter和ReceiveFilterFactory,但你还没有开始使用它们。如果你想使它们可以在您的应用程序中,您需要使用您所创建的RequestInfo,ReceiveFilter和ReceiveFilterFactory定义您的AppSession和AppServer。
-
为AppSession设置RequestInfo
public class YourSession : AppSession<YourSession, YourRequestInfo> { //More code... }
-
为AppServer设置RequestInfo和ReceiveFilterFactory
public class YourAppServer : AppServer<YourSession, YourRequestInfo> { public YourAppServer() : base(new YourReceiveFilterFactory()) { } }
完成这两件事情后,您的自定义的通信协议应该工作了。