在通信写完了以后,应用层接收到Socket抛上来的byte[],这个时候对于实际的写逻辑的开发者来说,这样的数据并不友好,我们就需要在应用层统一一个包的规则(应用层协议),处理完以后,然后再传给实际的逻辑层去处理。

以下是一个常用的Command模式。既接收到传递过来的包以后,根据Command(命令)来执行对应的Command(逻辑)。

我们假定我们的包(以下所有的包都指的是应用层的包,而非Socket层的包)分为 命令头/数据 两块。

public class InterUnit
{
public string Command;
public JToken Body;
}

因为采用Command模式,我们定义了一个接口ICommand

    public interface ICommand
{
InterUnit Execute(InterUnit unit);
}

命令的Command,如何跟实际逻辑对应起来,常用的有Ioc,但是你也可以硬编码,我采用的是Attribute的方式,来对应起来。

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class CommandAttribute : Attribute
{
public CommandAttribute(string command)
{
this.Command = command;
} public string Command;
}

对应起来以后,那就需要在接到包的地方,去根据Command找到对应的Class来执行逻辑。

public class CommandFactory
{
private Dictionary<string, ICommand> _commandMap; public CommandFactory()
{
if (_commandMap == null)
{
_commandMap = new Dictionary<string, ICommand>();
}
} /// <summary>
/// 通过反射将标注了CommandAttribute的实例,放入字典。
/// 不需要等到需要调用时,才去动态的注入。
/// </summary>
/// <param name="assembly"></param>
public void Init(params string[] assembly)
{
if (assembly != null)
{
foreach (string s in assembly)
{
var ass = Assembly.Load(s);
if (ass != null)
{
var types = ass.GetTypes();
foreach (var type in types)
{
CommandAttribute attr = type.GetCustomAttribute(typeof(CommandAttribute), false) as CommandAttribute;
if (attr != null)
{
if (attr.Command == null || attr.Command.Length == )
{
_commandMap[type.Name] = Activator.CreateInstance(type) as ICommand;
}
else
{
_commandMap[attr.Command] = Activator.CreateInstance(type) as ICommand;
}
}
}
}
}
}
} public void ExecuteCommand(SocketSession session, InterUnit unit)
{
if(_commandMap.ContainsKey(unit.Command))
{
ICommand command = _commandMap[unit.Command];
var rtv = command.Execute(unit);
if (rtv != null)
{
session.Send(BsonHelper.ToBson<InterUnit>(unit));
}
}
}
}

我在这里采用的是Bson的格式,作为数据来传递。

有一个地方需要注意的就是,在Send的时候,实际上我们并没有定义Socket的包的格式,因为在协议的地方已经处理了这个事情,会将你发送过去的数据,自动加上包头。

public interface IProtocol
{
byte[] OnDataReceivedCallBack(byte[] data, ref int offset); byte[] OnDataSendBefore(byte[] data);
} public class DefaultProtocol : IProtocol
{
public byte[] OnDataReceivedCallBack(byte[] data, ref int offset)
{
int length = BitConverter.ToInt32(data, offset);
int package_head = ;
int package_length = length + package_head;
byte[] buffer = null;
if (length > )
{
if (offset + package_length <= data.Length)
{
buffer = new byte[length];
Array.Copy(data, offset + package_head, buffer, , length);
offset += package_length;
}
}
else
{
offset = -;
}
return buffer;
} public byte[] OnDataSendBefore(byte[] data)
{
int length = data.Length;
var head = BitConverter.GetBytes(length);
byte[] buffer = new byte[data.Length + head.Length];
Buffer.BlockCopy(head, , buffer, , head.Length);
Buffer.BlockCopy(data, , buffer, head.Length, data.Length); return buffer;
}
}

写自己的Socket框架(三)的更多相关文章

  1. linux可用的跨平台C# .net standard2.0 写的高性能socket框架

    能在window(IOCP)/linux(epoll)运行,基于C# .net standard2.0 写的socket框架,可使用于.net Framework/dotnet core程序集,.使用 ...

  2. 写自己的Socket框架(一)

    本系列仅介绍可用于生产环境的C#异步Socket框架,如果您在其他地方看到类似的代码,不要惊讶,那可能就是我在参考开源代码时,直接“剽窃”过来的. 1.在脑海里思考一下整个socket的链接的处理流程 ...

  3. 写自己的socket框架(二)

    1.开始正常监听以后,就要开始接受数据了,整体流程图如下: 2.上一节看到我们在程序初始化的时候,初始化了很多个SocketConnection,用于管理客户端的链接,那应用层如何来操作,又什么时候来 ...

  4. Workerman:PHP的socket框架

    hi,我们今天来讲讲Workerman,什么是Workerman呢? 看看官网上的介绍 Workerman是一款开源高性能异步PHP socket框架.支持高并发,超高稳定性,被广泛的用于手机app. ...

  5. ZYSocket 4.3.5 SOCKET框架组 发布[NEW]

    最新代码请到 github: https://github.com/luyikk/ZYSOCKET 更新 4.3.5更新说明: 修复各种BUG. 重写了一份 protobuf-net 有什么用呢,不需 ...

  6. Jersey框架三:Jersey对HTTPS的支持

    Jersey系列文章: Jersey框架一:Jersey RESTful WebService框架简介 Jersey框架二:Jersey对JSON的支持 Jersey框架三:Jersey对HTTPS的 ...

  7. atitit.软件开发--socket框架选型--netty vs mina j

    atitit.软件开发--socket框架选型--netty vs mina j . Netty是由JBOSS提供的一个java开源框架 Apache mina 三.文档比较 mina文档多,,, 好 ...

  8. 从零开始实现一个简易的Java MVC框架(三)--实现IOC

    Spring中的IOC IoC全称是Inversion of Control,就是控制反转,他其实不是spring独有的特性或者说也不是java的特性,他是一种设计思想.而DI(Dependency ...

  9. 如果你想写自己的Benchmark框架

    目录 简介 八条军规 第一条军规 第二条军规 第三条军规 第四条军规 第五条军规 第六条军规 第七条军规 最后一条军规 总结 简介 使用过JMH的同学一定会惊叹它的神奇.JMH作为一个优秀的Bench ...

随机推荐

  1. 【原】FMDB源码阅读(三)

    [原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...

  2. Asp.Net WebApi核心对象解析(下篇)

    在接着写Asp.Net WebApi核心对象解析(下篇)之前,还是一如既往的扯扯淡,元旦刚过,整个人还是处于晕的状态,一大早就来处理系统BUG,简直是坑爹(好在没让我元旦赶过来该BUG),队友挖的坑, ...

  3. ASP.NET Core 1.1.0 Release Notes

    ASP.NET Core 1.1.0 Release Notes We are pleased to announce the release of ASP.NET Core 1.1.0! Antif ...

  4. Intellij idea添加单元测试工具

    1.idea 版本是14.0.0 ,默认带有Junit,但是不能自动生成单元测试,需要下载JunitGererator2.0插件 2.Settings -Plugins,下载 JunitGenerat ...

  5. HTML 事件(三) 事件流与事件委托

    本篇主要介绍HTML DOM中的事件流和事件委托. 其他事件文章 1. HTML 事件(一) 事件的介绍 2. HTML 事件(二) 事件的注册与注销 3. HTML 事件(三) 事件流与事件委托 4 ...

  6. Redis数据库

    Redis是k-v型数据库的典范,设计思想及数据结构实现都值得学习. 1.数据类型 value支持五种数据类型:1.字符串(strings)2.字符串列表(lists)3.字符串集合(sets)4.有 ...

  7. Node.js:理解stream

    Stream在node.js中是一个抽象的接口,基于EventEmitter,也是一种Buffer的高级封装,用来处理流数据.流模块便是提供各种API让我们可以很简单的使用Stream. 流分为四种类 ...

  8. B样条基函数的定义和性质

    定义:令U={u0,u1,…,um}是一个单调不减的实数序列,即ui≤ui+1,i=0,1,…,m-1.其中,ui称为节点,U称为节点矢量,用Ni,p(u)表示第i个p次(p+1阶)B样条基函数,其定 ...

  9. 网站里加入QQ在线客服

    1.开启"QQ在线状态"服务  http://jingyan.baidu.com/article/b24f6c823425a586bfe5da1f.html http://www. ...

  10. Android的Kotlin秘方(II):RecyclerView 和 DiffUtil

    作者:Antonio Leiva 时间:Sep 12, 2016 原文链接:http://antonioleiva.com/recyclerview-diffutil-kotlin/ 如你所知,在[支 ...