写自己的Socket框架(三)

在通信写完了以后,应用层接收到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 == 0)
                                {
                                    _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 = 4;
            int package_length = length + package_head;
            byte[] buffer = null;
            if (length > 0)
            {
                if (offset + package_length <= data.Length)
                {
                    buffer = new byte[length];
                    Array.Copy(data, offset + package_head, buffer, 0, length);
                    offset += package_length;
                }
            }
            else
            {
                offset = -1;
            }
            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, 0, buffer, 0, head.Length);
            Buffer.BlockCopy(data, 0, buffer, head.Length, data.Length);

            return buffer;
        }
    }

写自己的Socket框架(三)

时间: 2024-08-29 08:30:18

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

写自己的socket框架(二)

1.开始正常监听以后,就要开始接受数据了,整体流程图如下: 2.上一节看到我们在程序初始化的时候,初始化了很多个SocketConnection,用于管理客户端的链接,那应用层如何来操作,又什么时候来接受数据?于是我们便有了SocketSession,用于给应用层来管理整个会话过程,代码如下: public class SocketSession : IDisposable { public string SessionId { get; private set; } private Syste

写自己的Socket框架(一)

本系列仅介绍可用于生产环境的C#异步Socket框架,如果您在其他地方看到类似的代码,不要惊讶,那可能就是我在参考开源代码时,直接“剽窃”过来的. 1.在脑海里思考一下整个socket的链接的处理流程,于是便有了下图. 2.首先就开始监听,代码如下: public override bool Start() { this._socket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, P

企业级应用框架(三)三层架构之数据访问层的改进以及测试DOM的发布

在上一篇我们在宏观概要上对DAL层进行了封装与抽象.我们的目的主要有两个:第一,解除BLL层对DAL层的依赖,这一点我们通过定义接口做到了:第二,使我们的DAL层能够支持一切数据访问技术,如Ado.net,EF,linq To Sql,这一点我们实现的不是很完美,仍有很大的改进空间,本文将加以改进. 在此之前我们来看一下我们最新的dom(PS:经过两天的赶工,我们的dom已经相对成熟,其中BLL层已经被我高度抽象化了,并且引进了业务上文文的概念:DAL层除了具体的技术实现尚为完成,其他方面已经相

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

atitit.软件开发--socket框架选型--netty vs mina j . Netty是由JBOSS提供的一个java开源框架 Apache mina 三.文档比较 mina文档多,,, 好几倍... 作者:: 老哇的爪子 Attilax 艾龙,  EMAIL:[email protected] 转载请注明来源: http://blog.csdn.net/attilax 四.UDP协议传输 1. netty将UDP无连接的特性暴露出来:而mina对UDP进行了高级层次的抽象,可以把UD

一起talk C栗子吧(第一百四十九回:C语言实例--socket通信三)

各位看官们,大家好,上一回中咱们说的是socket通信的例子,这一回咱们继续说该例子.闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,我们在上一回中介绍了socket通信的步骤,当时提到了实现这些步骤使用的系统调用,当时有些看官不理解这些系统调用,今天我们趁热打铁来介绍这些系统调用. int socket(int domain, int type, int protocol) 该函数用来创建一个socket; 该函数的三个参数分别对应socket的三个属性:域,类型和协议: 该函数运

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

Spring中的IOC IoC全称是Inversion of Control,就是控制反转,他其实不是spring独有的特性或者说也不是java的特性,他是一种设计思想.而DI(Dependency Injection),即依赖注入就是Ioc的一种实现方式.关于Ioc和DI的具体定义和优缺点等大家可以自行查找资料了解一下,这里就不详细赘述,总之spring的IoC功能很大程度上便捷了我们的开发工作. 在实现我们的Ioc之前,我们先了解一下spring的依赖注入,在spring中依赖注入有三种方式

synapse socket总结三:心跳(Heartbeat)

首先转载一篇关于心跳的博文解释: 所谓的心跳包就是客户端定时发送简单的信息给服务器端告诉它我还在而已.代码就是每隔几分钟发送一个固定信息给服务端,服务端收到后回复一个固定信息如果服务端几分钟内没有收到客户端信息则视客户端断开.比如有些通信软件长时间不使用,要想知道它的状态是在线还是离线就需要心跳包,定时发包收包.发包方:可以是客户也可以是服务端,看哪边实现方便合理.一般是客户端.服务器也可以定时轮询发心跳下去.心跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户

类集框架(三)

1. Map和HashMap的使用方法 2. JDK帮助文档的使用方法 1. Map和HashMap的使用方法 2. JDK帮助文档的使用方法 帮助文档下载chm格式的英文版, 在索引里面搜索Map 1 import java.util.Map; 2 import java.util.HashMap; 3 4 public class Test{ 5 public static void main(String args []){ 6 HashMap<String,String> hashMa

socket框架续,异步socket

上一篇对socket进行了简单的封装,但是由于send和recv都是同步的,真正使用的时候一般都需要异步的,如果让应用层自己负责维护异步线程,那这个框架就不实用了,所以异步收发还是要有的. 不知道怎么说起,先占坑以后再慢慢说吧. 我的实现方法: 1.创建SendBuffer和RecvBuffer,包装发送和接收的消息. 2.使用循环队列创建发送队列和接收队列,异步调用只需要将消息加入队列.(循环队列的实现可以参考 http://www.cnblogs.com/wolfred7464/p/4337