实现SuperSocket模板协议FixedHeaderReceiveFilter与msgpack结合
来源:互联网 发布:淘宝上丰胸霜可信吗 编辑:程序博客网 时间:2024/05/17 02:37
实现SuperSocket模板协议FixedHeaderReceiveFilter与msgpack结合
在群里有个群友在群里一直在问使用FixedHeaderReceiveFilter与msgpack结合的实现问题,搞了几天都没有搞定,于是就写了这个文章来说明。希望能帮助到他。
SuperSocket的内置的常用协议实现模版文档链接
msgpack的官网
SuperSocket 简称为SS
首先要定义一下协议
/// +-------+---+-------------------------------+/// |request| l | |/// | name | e | request body |/// | (4) | n | |/// | |(4)| |/// +-------+---+-------------------------------+
如上说明,request name 占4个字节,这个是用来寻找SS里面的命令对象,根据是根据命令类名称来查找的。
len是表示 request body序列化成byte后的长度。
request body 是表示我们用msgpack序列化后的内容。
*注意:*request name 和len占用的字节是可以自己定义的
协议搞懂后,我们就需要来编写代码了,需要编写如下类:
- MsgPackReceiveFilter要继承FixedHeaderReceiveFilter,作用是实现协议解析
- MsgPackReceiveFilterFactory要继承IReceiveFilterFactory,作用是使得server能知道是用哪个协议解析对象来做协议解析。
- MsgPackServer继承AppServer,作用是加载协议解析工厂的。
- MsgPackSession作用参考一个Telnet示例
- MsgPackCommand作用参考一个Telnet示例,同时实现request body的反序列化
- 实现一个命令Test继承MsgPackCommand
- MyData一个要传输的数据结构
下面来看下代码的实现
using System;using System.Collections.Generic;using System.Linq;using System.Text;using SuperSocket.Common;using SuperSocket.Facility.Protocol;using SuperSocket.SocketBase.Protocol;namespace FixedHeader{ /// +-------+---+-------------------------------+ /// |request| l | | /// | name | e | request body | /// | (4) | n | | /// | |(4)| | /// +-------+---+-------------------------------+ public class MsgPackReceiveFilter : FixedHeaderReceiveFilter<BinaryRequestInfo> { public MsgPackReceiveFilter() : base(8) { } protected override int GetBodyLengthFromHeader(byte[] header, int offset, int length) { var headerData = new byte[4]; Array.Copy(header,offset+4,headerData,0,4); return BitConverter.ToInt32(headerData, 0); } 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)); } }}
首先我们看到构造函数base(8)里面的输入了一个8,这个8是协议头的长度,也就是request name 加 len的长度。
然后再看实现了方法GetBodyLengthFromHeader,从名字上看,就可以知道是根据协议头的数据来获取打包的数据的长度。
这个方法有三个参数
- byte[] header 缓存的数据,这个并不是单纯只包含协议头的数据
- int offset 要取的数据的偏移量,也就是在header里面从offset开始就是我们从客户的发送过来的数据。
- int length 就是我在base(8)这里设置的长度也就是8.
在这里我们可以取得到协议头的数据,就是在header从偏移量offset开始截取长度为length的部分数组,就是我们的协议头了。但是我们的协议头是8位,要取打包数据的长度那么就需要从偏移offset上再加4位,代码就是
var headerData = new byte[4];Array.Copy(header,offset+4,headerData,0,4);
然后再把取到的数据转换成为int类型也就是
BitConverter.ToInt32(headerData, 0);
ss就可以根据这个长度来帮助我们获取到打包的数据。然后传给方法ResolveRequestInfo。我们需要实现这个方法。这个方法有四个参数:
- header 我们的协议头的数据
- bodyBuffer 缓存的数据,这个并不是只单纯包含打包数据的
- offset 打包数据在bodyBuffer里面开始的位置
- int length 打包数据的长度
ResolveRequestInfo 返回的是 FixedHeaderReceiveFilter的一个泛型,这个对象是用于注入实现命令的。我们这里使用的是BinaryRequestInfo。
Encoding.UTF8.GetString(header.Array, header.Offset, 4)
这个代码是把协议头的前四位转换成为字符串,这字符串是用于查找要执行的命令的。
bodyBuffer.CloneRange(offset, length)
这个代码是截取我们需要的数据,这个数据也将是会传给执行命令的。
到这里我们的MsgPackReceiveFilter协议解析已经完成了,然后再实现一个工厂来使得server能够加载到MsgPackReceiveFilter来解析我们的协议
using System;using System.Collections.Generic;using System.Linq;using System.Net;using System.Text;using SuperSocket.SocketBase;using SuperSocket.SocketBase.Protocol;namespace FixedHeader{ public class MsgPackReceiveFilterFactory : IReceiveFilterFactory<BinaryRequestInfo> { public IReceiveFilter<BinaryRequestInfo> CreateFilter(IAppServer appServer, IAppSession appSession, IPEndPoint remoteEndPoint) { return new MsgPackReceiveFilter(); } }}
MsgPackReceiveFilterFactory的实现相对简单,就是实现接口IReceiveFilterFactory的方法返回一个MsgPackReceiveFilter对象,这个就用多做解释
然后要使得server能够加载到,还需要再实现一个server
using System;using System.Collections.Generic;using System.Linq;using System.Text;using SuperSocket.SocketBase;using SuperSocket.SocketBase.Protocol;namespace FixedHeader{ public class MsgPackServer : AppServer<MsgPackSession, BinaryRequestInfo> { public MsgPackServer() : base(new MsgPackReceiveFilterFactory()) { } }}
只要实例化工厂MsgPackReceiveFilterFactory然后传给构造函数就可以了。
然后再实现一个MsgPackSession这个只要继承AppSession就可以了,不用做任何的实现。
using System;using System.Collections.Generic;using System.Linq;using System.Text;using SuperSocket.SocketBase;using SuperSocket.SocketBase.Protocol;namespace FixedHeader{ public class MsgPackSession : AppSession<MsgPackSession, BinaryRequestInfo> { }}
然后再实现一个MsgPackCommand。这个主要是为了把打包发送过来的数据统一反序列列化,这样只要继承MsgPackCommand的类,都可以直接得到想要的对象。
using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Text;using MsgPack.Serialization;using SuperSocket.SocketBase.Command;using SuperSocket.SocketBase.Protocol;namespace FixedHeader{ public abstract class MsgPackCommand<TMsgPack> : CommandBase<MsgPackSession, BinaryRequestInfo> where TMsgPack : class { public override void ExecuteCommand(MsgPackSession session, BinaryRequestInfo requestInfo) { var serializer = SerializationContext.Default.GetSerializer<TMsgPack>(); using (var stream = new MemoryStream(requestInfo.Body)) { var unpackedObject = serializer.Unpack(stream) as TMsgPack; ExecuteCommand(session, unpackedObject); } } public abstract void ExecuteCommand(MsgPackSession session, TMsgPack pack); }}
最后再做一个测试的命令和一个数据结构,
using System;using System.Collections.Generic;using System.Linq;using System.Text;using SuperSocket.SocketBase.Command;using SuperSocket.SocketBase.Protocol;namespace FixedHeader{ public class Test : MsgPackCommand<MyData> { public override void ExecuteCommand(MsgPackSession session, MyData pack) { Console.WriteLine(pack.Name+":"+ pack.Other); } }}
namespace FixedHeader{ public class MyData { public string Name { get; set; } public string Other { get; set; } }}
到这里就服务端就可以了。接下来还需要实现一个客户端来做简单的测试,这个没有什么好说的,直接上代码:
using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Net.Sockets;using System.Text;using MsgPack.Serialization;namespace FixedHeaderClient{ class Program { static void Main(string[] args) { var socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp); socket.Connect("127.0.0.1",2012); using (var stream = new MemoryStream()) { var serializer = SerializationContext.Default.GetSerializer<MyData>(); var myData = new MyData() { Name = "Test", Other = "abcd" }; serializer.Pack(stream, myData); //var commandData = new byte[4];//协议命令只占4位 var commandData = Encoding.UTF8.GetBytes("Test");//协议命令只占4位,如果占的位数长过协议,那么协议解析肯定会出错的 var dataBody = stream.ToArray(); var dataLen = BitConverter.GetBytes(dataBody.Length);//int类型占4位,根据协议这里也只能4位,否则会出错 var sendData = new byte[8+dataBody.Length];//命令加内容长度为8 // +-------+---+-------------------------------+ // |request| l | | // | name | e | request body | // | (4) | n | | // | |(4)| | // +-------+---+-------------------------------+ Array.ConstrainedCopy(commandData, 0, sendData, 0, 4); Array.ConstrainedCopy(dataLen, 0, sendData, 4,4); Array.ConstrainedCopy(dataBody, 0, sendData, 8, dataBody.Length); for (int i = 0; i < 1000; i++) { socket.Send(sendData); } } Console.Read(); } }}
源码托管
- 实现SuperSocket模板协议FixedHeaderReceiveFilter与msgpack结合
- SuperSocket与Netty之实现protobuf协议,包括服务端和客户端
- 使用SuperSocket实现TLV自定义协议网络通信的Demo
- XML与ASP简单结合实现HTML模板功能
- XML与ASP简单结合实现HTML模板功能
- XML与ASP简单结合实现HTML模板功能
- XML与ASP简单结合实现HTML模板功能
- msgpack
- SuperSocket入门(五)-常用协议实现模版及FixedSizeReceiveFilter示例_0
- SuperSocket
- SuperSocket
- 使用jmeter 封装MSGPACK协议做压力测试
- SuperSocket 入门,实现客户端和服务端消息互发
- SpringMVC结合freemarker模板回显数据的实现
- 结合泛型与模板的STL.NET
- 结合泛型与模板的STL.NET
- python WEB tornado框架与mako模板的结合
- Ajax与PHP结合实现登录验证
- 升级jdk8后系统报错解决:java.lang.RuntimeException: java.io.IOException: invalid constant type: 18
- PowerManagerService电源管理和Wacklock锁申请与释放机制
- 黑马程序员-学习笔记之Java基础
- PHP跨域Ajax解决方案
- Wordpress启用多站点和子站独立域名绑定教程
- 实现SuperSocket模板协议FixedHeaderReceiveFilter与msgpack结合
- 海南PHP程序员-李清波
- leetcode: (260) Single Number III
- mysql修改表、字段、库的字符集
- io.js
- c++设计模式-----责任链模式
- linux网络编程
- Android使用属性动画property animation,实现分散式弹出菜单
- 易语言调用js实现md5加密