如何使用自定义消息?--ESFramework 4.0 快速上手(04)

  在ESFramework 4.0 快速上手一文中,我们讲述了如何使用Rapid引擎可以快速地上手ESFramework开发,文中介绍了使用ESPlus.Application.CustomizeInfo命名空间下的类可以发送和处理自定义消息,本文我们就通过一个简单的例子来深入讲解如何使用自定义消息。

  例子的场景很简单:假设客户端登陆到服务器之后,要求请求加入某个组,服务端收到该请求后,处理该请求,并给客户端相应的回复 -- 是否加入成功,客户端收到回复后,即可作出相应的处理。

 

一.定义消息类型和消息协议Contract

  这个场景涉及到两种类型的消息:请求加入组(客户端发给服务器),加入组的结果(服务器回复给客户端)。于是,我们可以定义这两个消息类型:

        public static class InformationTypes
        {
            /// <summary>
            /// 请求加入组 Client =》 Server 。对应的消息体为 JoinGroupContract

            /// </summary>
            public const int JoinGroup = 1;

            /// <summary>
            /// 加入组的结果 Server =》 Client 。对应的消息体为 JoinGroupResultContract
            /// </summary>
            public const int JoinGroupResult = 2;
        }

  另外,我们可以客户端发给服务器的请求以及服务器给客户端的回复分别用协议类JoinGroupContract和JoinGroupResultContract封装起来:

        [Serializable]
        public class JoinGroupContract
        {
            public JoinGroupContract() { }
            public JoinGroupContract(string _groupID, string _groupPwd)
            {
                this.groupID = _groupID;
                this.groupPwd = _groupPwd;
            }

            #region GroupID
            private string groupID = "";
            /// <summary>
            /// 请求加入组的ID
            /// </summary>
            public string GroupID
            {
                get { return groupID; }
                set { groupID = value; }
            }
            #endregion

            #region GroupPwd
            private string groupPwd = "";
            /// <summary>
            /// 请求加入组的密码
            /// </summary>
            public string GroupPwd
            {
                get { return groupPwd; }
                set { groupPwd = value; }
            } 
            #endregion
        }

        [Serializable]
        public class JoinGroupResultContract
        {
            public JoinGroupResultContract(){}
            public JoinGroupResultContract(bool _succeed)
            {
                this.succeed = _succeed;
            }

            #region Succeed
            private bool succeed = true;
            /// <summary>
            /// 加入组是否成功
            /// </summary>
            public bool Succeed
            {
                get { return succeed; }
                set { succeed = value; }
            } 
            #endregion
        }

  当然,这里的协议类非常简单,而对于我们实际的应用,协议类中封装很多的信息都是可以的。

 

二.客户端向服务器发送请求

  好了,客户端在引擎初始化成功之后,就可以向服务器发送加入组G001的请求了:

   //向服务器请求 加入G100组
   JoinGroupContract JoinGroupContract = new JoinGroupContract("G100", "123456");
   rapidPassiveEngine.CustomizeInfoOutter.Send(InformationTypes.JoinGroup, ESBasic.Helpers.SerializeHelper.SerializeObject(JoinGroupContract));

 

三.服务器处理请求,并发送回复给客户端

  服务端通过实现ESPlus.Application.CustomizeInfo.Server.ICustomizeInfoBusinessHandler接口的HandleInformation方法来处理该请求:

        private ICustomizeInfoController customizeInfoController = ......;

        //服务端处理消息
        public void HandleInformation(string sourceUserID, int informationType, byte[] info)
        {
            if(informationType == InformationTypes.JoinGroup)
            {
                JoinGroupContract joinGroupContract = (JoinGroupContract)ESBasic.Helpers.SerializeHelper.DeserializeBytes(info, 0, info.Length);
                string groupID = joinGroupContract.GroupID;  
              
                // ........ (逻辑处理)

                JoinGroupResultContract resContract = new JoinGroupResultContract(true) ;//同意加入
                //向用户发送回复消息
                this.customizeInfoController.Send(sourceUserID, InformationTypes.JoinGroupResult, SerializeHelper.SerializeObject(resContract));
                return;
            }
        }

  

四.客户端处理服务器的回复

  接下来,客户端也可以通过实现ESPlus.Application.CustomizeInfo.Passive.ICustomizeInfoBusinessHandler接口的HandleInformationFromServer方法来处理服务器的回复:

        //客户端处理消息
        public void HandleInformationFromServer(int informationType, byte[] info)
        {
            if (informationType == InformationTypes.JoinGroupResult)
            {
                JoinGroupResultContract resContract = (JoinGroupResultContract)SerializeHelper.DeserializeBytes(info, 0, info.Length);
                if (resContract.Succeed)
                {
                    //...... 加入成功了,呵呵
                }
                return;
            }
        }

 

  这个demo简单地演示了消息类型的定义、协议类的定义、以及客户端向服务器发送请求、服务器处理请求并回复客户端的一个完整的处理流程。通过自定义消息,我们可以在服务端与客户端之间实现非常复杂的协作。所以,哪怕是使用ESFramework的快速引擎,我们也可以做很多很复杂的事情了。

     有一点要特别注意,那就是尽可能使消息的尺寸小,在相同的频率下,消息越小,通信的效率越高。在本文的demo中,我们采用的是.NET自带的二进制序列化器将协议对象转化为byte[],而使用这个序列化器,所得到的byte[]通常都非常大,而消息越大,将使得服务端与客户端通信的负担增大。所以,如果有自己更好更简洁的序列化方式,建议不要采用.NET自带的二进制序列化器。

 

ESFramework 4.0 概述 (文末包含最新版本的ESFramework4.0以及相关demo、帮助文档下载)

《ESFramework 4.0 快速上手》系列所有文章

《ESFramework 4.0 高级进阶》系列所有文章

 

 

 

时间: 2024-10-27 19:08:46

如何使用自定义消息?--ESFramework 4.0 快速上手(04)的相关文章

ESFramework 4.0 快速上手(06) -- Rapid引擎(续)

<ESFramework 4.0 快速上手>系列介绍的都是如何使用Rapid引擎(快速引擎) -- RapidServerEngine 和 RapidPassiveEngine.其实,大家可以将这两个引擎看作是两个壳,内部包装的才是真正的ESFramework的网络引擎, ESFramework支持很多种网络引擎(客户端/服务端.二进制协议/文本协议.TCP/UDP),而RapidServerEngine和RapidPassiveEngine采用的是基于TCP和二进制协议的服务端引擎和客户端引

重登陆模式 --ESFramework 4.0 快速上手(07)

在ESFramework框架中基于TCP的服务端引擎(当然也包括Rapid引擎)都采用了这样一条规则:默认情况下,客户端与服务器成功建立TCP连接以后,服务端会从客户端发过来的第一条消息中取出消息头的UserID属性的值,并将其与对应的TCP连接绑定起来.这样,服务端就知道每一个TCP连接所对应的用户UserID,而当我们要求服务端向某个客户端发送消息时,服务端就知道通过哪个TCP连接进行发送了.TCP连接与UserID是一一对应的,一个TCP连接只能对应一个UserID,同样的,一个UserI

聊天系统Demo,增加Silverlight客户端(附源码)-- ESFramework 4.0 快速上手(09)

      在ESFramework 4.0 快速上手 -- 入门Demo,一个简单的IM系统(附源码)一文中,我们介绍了使用ESFramework的Rapid引擎开发的winform聊天程序,本文我们将在之前demo的基础上添加使用ESFramework.SL开发的Silverlight客户端.这样一来,不仅Silverlight客户端之间可以相互通信,Silverlight客户端还可以跟winform客户端进行通信.如果不了解在Silverlight中如何使用ESFramework,可以先看

使用紧凑的序列化器,数倍提升性能 —— ESFramework 4.0 快速上手(11)

在分布式通信系统中,网络传递的是二进制流,而内存中是我们基于对象模型构建的各种各样的对象,当我们需要将一个对象通过网络传递给另一个节点时,首先需要将其序列化为字节流,然后通过网络发送给目标节点,目标节点接收后,再反序列化为对象实例.在ESFramework体系中,也是遵循同样的规则.       ESFramework称这些需要经过网络传递的对象称之为协议类(Contract),协议类通常只是一个简单的数据结构封装,用于保存状态的一个哑类(不包含任何方法,从object继承的除外),有点类似于与

客户端登录验证 -- ESFramework 4.0 快速上手(15)

      在之前版本的Rapid引擎中,是没有提供客户端登陆验证的机制的,如果要验证用户的帐号密码信息,我们只有自己手动通过自定义信息来实现.在2011.04.25发布的新版本中,客户端Rapid引擎,则内置了在初始化时验证用户的帐号密码的功能,这使得登录验证变得更加简单.   一. ESPlus.Application.Basic 空间的支持       为了实现验证用户账号密码的功能,ESPlus.Application.Basic 命名空间增加了几个基础设施. (1)ESPlus.App

离线消息如何实现?-- ESFramework 4.0 快速上手(02)

在ESFramework 4.0 快速上手一文中,主要介绍了如何使用ESPlus.Rapid命名空间中的引擎来快速地构建基于TCP的网络通信系统,即使是使用ESPlus.Rapid来进行ESFramework快速开发,也还有很多可以介绍的内容,于是,我想再多写几篇文章来说明现实通信系统中的一些常见需求如何使用ESFramework快速实现.本文是为第一篇,介绍离线消息的原理和实现.   一.如何截获离线消息 阅读了ESFramework 4.0 快速上手朋友都知道,一个在线用户给另一个用户发送文

异常日志—— ESFramework 4.0 快速上手(03)

   ESFramework框架(包括ESPlus.ESPlatform)实现时就内置了相对完整的日志功能,几乎所有的异常(Exception)和错误信息都会被记录到日志.通过查看日志记录,我们可以了解到程序在运行的过程中出现了哪些非正常的状况,并且,详细的日志记录可以帮我们迅速定位问题,并解决问题.(关于我对日志记录的更多认识,可以参看我的博文我的架构经验小结(五)-- 日志记录 )   一.IAgileLogger接口     首先,ESFramework框架使用ESBasic.Logger

聊天系统Demo,增加文件传送功能(附源码)-- ESFramework 4.0 快速上手(14)

      本文我们将介绍在ESFramework 4.0 快速上手(08) -- 入门Demo,一个简单的IM系统(附源码)的基础上,增加文件传送的功能.如果不了解如何使用ESFramework提供的文件传送功能,可以先看看ESFramework 4.0 快速上手(13) -- 文件传送,如此简单一文的详细介绍.       本Demo可演示以下与文件传送相关的特性: (1)发送方请求发送文件,接收方可以同意或拒绝接收文件. (2)文件传送的过程中,收发的任何一方都可以通过事件了解文件传送的实

判定生死的心跳机制 --ESFramework 4.0 快速上手(07)

      在Internet上采用TCP进行通信的系统,都会遇到一个令人头疼的问题,就是"掉线".而"TCP掉线"这个问题远比我们通常所能想象的要复杂的多 -- 网络拓扑纷繁复杂.而从始节点A到终节点B之间可能要经过N多的交换机.路由器.防火墙等等硬件设备,每个硬件设备的相关设定也不统一,再加上网络中可能出现的拥塞.延迟等,使得我们在编程时,处理掉线也非常棘手.   一.从程序的角度看待TCP掉线       TCP掉线的原因可能多种多样.不一而足,比如,客人的电