在通信写完了以后,应用层接收到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. Fis3的前端工程化之路[三大特性篇之内容嵌入]

    Fis3版本:v3.4.22 Fis3的三大特性 资源定位:获取任何开发中所使用资源的线上路径 内容嵌入:把一个文件的内容(文本)或者base64编码(图片)嵌入到另一个文件中 依赖声明:在一个文本文 ...

  2. 恢复SQL Server被误删除的数据(再扩展)

    恢复SQL Server被误删除的数据(再扩展) 大家对本人之前的文章<恢复SQL Server被误删除的数据> 反应非常热烈,但是文章里的存储过程不能实现对备份出来的日志备份里所删数据的 ...

  3. UML课程复习重点

    第一章 一.UML图示建模工具 二.UML--统一建模语言,以图形符号为基础,描述软件模型既简洁又清晰.它不是开发方法,是独立于任何开发方法之外的语言.它用于描述软件系统分析.设计和实施中的各种模型. ...

  4. Node.js:理解stream

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

  5. mybatis plugins实现项目【全局】读写分离

    在之前的文章中讲述过数据库主从同步和通过注解来为部分方法切换数据源实现读写分离 注解实现读写分离: http://www.cnblogs.com/xiaochangwei/p/4961807.html ...

  6. [转载]SQL语句中的日期计算

    1. 本月的第一天SELECT  DATEADD(mm,  DATEDIFF(mm,0,getdate()),  0) 2. 本月的最后一天SELECT  dateadd(ms,-3,DATEADD( ...

  7. 安卓客户端a标签长按弹框提示解决办法

    昨天工作时候发现一个bug,是关于a标签的,在安卓客户端中,如果是a标签的话,长按会出现一个弹框,如图所示 是因为安卓客户端的长按触发机制,以后进行wap端开发的时候,如果用到跳转页面尽量不要用a标签 ...

  8. 如何区别数据库删除语句drop与delete与truncate?

    1.delete:删除数据表中的行(可以删除某一行,也可以在不删除数据表的情况下删除所有行) 删除某一行:delete from 数据表名称 where 列名称=值: 删除所有行:delete*fro ...

  9. 记:MySQL 5.7.3.0 安装 全程截图

    前言: 下一个班快讲MySQL数据库了,正好把服务器里面的MySQL卸了重装了一下. 截个图,作为笔记.也正好留给需要的朋友们. 目录: 下载软件 运行安装程序 安装程序欢迎界面 许可协议 查找更新 ...

  10. php+websocket搭建简易聊天室实践

    1.前言 公司游戏里面有个简单的聊天室,了解了之后才知道是node+websocket做的,想想php也来做个简单的聊天室.于是搜集各种资料看文档.找实例自己也写了个简单的聊天室. http连接分为短 ...