Socket开发框架之消息的回调处理

Socket开发框架之消息的回调处理

在一般的Socket应用里面,很多时候数据的发送和接收是分开处理的,也就是我们发送一个消息,不知道这个请求消息什么时候得到应答消息,而且收到对应的应答消息的时候,如果操作界面的内容,也是需要特别处理的,因为它们和界面线程是不在一起的。如果我们在发送消息的时候,能够给一段回调的代码给收到应答消息的时候处理,那么就会方便很多。本文主要介绍如何在Socket应用里面,通过回调函数的处理,实现收到应答消息的时候能够调用对应的函数。

1、回调函数的设计

在上一篇的随笔里面,介绍了基于Json的Socket消息的实体类设计,其中包括了消息回调ID和是否在调用后移除回调两个属性,这个是用来为回调处理服务的,如下所示。

也就是在通用消息对象BaseMessage类里面添加下面两个属性。

但我们需要发送消息的时候,我们把回调的ID添加到本地集合里面,得到应答的时候,在从集合里面提出来,执行就可以了。

        /// <summary>
        /// 发送通用格式的数据对象
        /// </summary>
        /// <param name="data">通用的消息对象</param>
        /// <returns></returns>
        public bool SendData(BaseMessage data, Delegate callBack = null)
        {
            AddCallback(callBack, data);//添加回调集合

            var toSendData = PackMessage(data);
            var result = SendData(toSendData);

            return result;
        }

        /// <summary>
        /// 记录回调的函数信息
        /// </summary>
        /// <param name="callBack"></param>
        /// <param name="msg"></param>
        private void AddCallback(Delegate callBack, BaseMessage msg)
        {
            if (callBack != null)
            {
                Guid callbackID = Guid.NewGuid();
                ResponseCallbackObject responseCallback = new ResponseCallbackObject()
                {
                    ID = callbackID,
                    CallBack = callBack
                };

                msg.CallbackID = callbackID;
                callBackList.Add(responseCallback);
            }
        }

在服务端,需要根据请求的消息构建应答内容,因此我们在应答请求的时候,需要把请求的回调ID给复制到应答的消息体里面,如下所示。

        /// <summary>
        /// 封装数据进行发送(复制请求部分数据)
        /// </summary>
        /// <returns></returns>
        public BaseMessage PackData(BaseMessage request)
        {
            BaseMessage info = new BaseMessage()
            {
                MsgType = this.MsgType,
                Content = this.SerializeObject(),
                CallbackID = request.CallbackID
            };

            if(!string.IsNullOrEmpty(request.ToUserId))
            {
                info.ToUserId = request.FromUserId;
                info.FromUserId = request.ToUserId;
            }

            return info;
        }

2、本地回调函数的处理及界面处理

调用方在收到服务器的应答消息的时候,会根据回调的ID ,从本地集合里面调出来并执行处理,实现了我们回调的操作。

                var md5 = MD5Util.GetMD5_32(message.Content);
                if (md5 == message.MD5)
                {
                    InvokeMessageCallback(message, message.DeleteCallbackAfterInvoke);//触发回调

                    OnMessageReceived(message);//给子类重载
                }

        /// <summary>
        /// 执行回调函数
        /// </summary>
        /// <param name="msg">消息基础对象</param>
        /// <param name="deleteCallback">是否移除回调</param>
        private void InvokeMessageCallback(BaseMessage msg, bool deleteCallback)
        {
            var callBackObject = callBackList.SingleOrDefault(x => x.ID == msg.CallbackID);
            if (callBackObject != null)
            {
                if (deleteCallback)
                {
                    callBackList.Remove(callBackObject);
                }
                callBackObject.CallBack.DynamicInvoke(msg);
            }
        }

这样,我们在调用的时候,传入一个回调的Action,让收到消息后进行动态执行就可以了。例如在登陆的时候,我们如果需要在登陆成功后显示主窗体,那么可以执行下面的处理代码。

            var request = new AuthRequest(userNo, password);
            var message = request.PackData();
            Singleton<CommonManager>.Instance.Send(message, (msg) =>
            {
                var instance = Singleton<CommonManager>.Instance;
                try
                {
                    var response = JsonTools.DeserializeObject<AuthResponse>(msg.Content);
                    if (response.ValidateResult == 0)
                    {
                        instance.ShowLoadFormText("登录成功,加载基础数据。。。。");

                        //放置初始化代码
                        Portal.gc.User = new User(userNo);
                        instance.SetClientId(userNo);

                        instance.ShowMainForm();
                        instance.CloseLoadForm();
                    }
                    else
                    {
                        instance.CloseLoadForm();
                        instance.ShowMessage("登录失败:" + response.Message);
                        instance.ShowLogin();
                    }
                }
                catch (Exception ex)
                {
                    instance.ShowMessage("初始化异常:" + ex.Message);
                    instance.Exit();
                }
            });

或者我们来看看另外一个例子,这个例子是在用户登陆的时候,请求一次在线用户列表,如果用户在线,那么在界面上展示列表,具体操作代码如下所示,也是利用了回调函数的处理方式。

        /// <summary>
        /// 发送获取在线用户列表的请求,并在收到应答数据后进行本地界面更新
        /// </summary>
        private void RefreshUser()
        {
            CommonRequest request = new CommonRequest(DataTypeKey.UserListRequest);
            var data = request.PackData();

            Singleton<CommonManager>.Instance.Send(data, (msg) =>
            {
                UserListResponse response = JsonTools.DeserializeObject<UserListResponse>(msg.Content);
                if (response != null)
                {
                    this.InvokeUI(() =>
                    {
                        this.listView1.Items.Clear();
                        foreach (CListItem item in response.UserList)
                        {
                            if (item.Value != Portal.gc.User.UserNo)
                            {
                                this.listView1.Items.Add(item.Text, 0);
                            }
                        }
                    });
                }
            });
        }

例如,客户端登陆几个用户后,用户可以获得在线用户列表,界面展示如下所示。

以上就是我们在Socket应用里面处理回调函数的实现过程,这样处理可以很好利用回调代码来封装处理的细节,对于理解相关的应答操作也是很直观的。

时间: 2024-10-09 19:41:47

Socket开发框架之消息的回调处理的相关文章

Socket开发框架之数据加密及完整性检查

在前面两篇介绍了Socket框架的设计思路以及数据传输方面的内容,整个框架的设计指导原则就是易于使用及安全性较好,可以用来从客户端到服务端的数据安全传输,那么实现这个目标就需要设计好消息的传输和数据加密的处理.本篇主要介绍如何利用Socket传输协议来实现数据加密和数据完整性校验的处理,数据加密我们可以采用基于RSA非对称加密的方式来实现,数据的完整性,我们可以对传输的内容进行MD5数据的校验对比. 1.Socket框架传输内容分析 前面介绍过Socket的协议,除了起止标识符外,整个内容是一个

Socket开发框架之数据传输协议

我在前面一篇随笔<Socket开发框架之框架设计及分析>中,介绍了整个Socket开发框架的总体思路,对各个层次的基类进行了一些总结和抽象,已达到重用.简化代码的目的.本篇继续分析其中重要的协议设计部分,对其中消息协议的设计,以及数据的拆包和封包进行了相关的介绍,使得我们在更高级别上更好利用Socket的特性. 1.协议设计思路 对Socket传输消息的封装和拆包,一般的Socket应用,多数采用基于顺序位置和字节长度的方式来确定相关的内容,这样的处理方式可以很好减少数据大小,但是这些处理对我

ZeroMQ接口函数之 :zmq_msg_send – 从一个socket发送一个消息帧

ZeroMQ 官方地址 :http://api.zeromq.org/4-0:zmq_msg_send zmq_msg_send(3) ØMQ Manual - ØMQ/3.2.5 Name zmq_msg_send – 从一个socket发送一个消息帧 Synopsis int zmq_msg_send (zmq_msg_t *msg, void *socket, int flags); Description zmq_msg_send函数和zmq_sendmsg(3)函数是完全相同的,只是z

Socket开发框架之框架设计及分析

虽然在APP应用.Web应用.Winform应用等大趋势下,越来越多的企业趋向于这些应用系统开发,但是Socket的应用在某些场合是很必要的,如一些停车场终端设备的接入,农业或者水利.压力监测方面的设备数据采集等,以及常见的IM(即时通讯,如腾讯QQ.阿里旺旺等)的客户端,都可以采用Socket框架进行相关的数据采集和信息通讯用途的,Socket应用可以做为APP应用.Web应用和Winform应用的补充. 1.Socket应用场景 一般情况下,客户端和服务端进行Socket连接,需要进行数据的

[objective-c] 04 - 消息机制 回调 目标-方法回调

本章主要讲解回调的概述以及具有目标-动作回调接口的组件如何使用. 1.回调 回调,也叫事件触发,在底层开发中也就是服务或中断服务.其产生过程较为复杂,所有我们在此不会展开讲解.只是单纯讲解如果配置回调. 在使用一些较为复杂,或者和用户有交互类型的组件时.我们通常需要根据组件触发的事件来做出相应的响应. 比如我们使用一个开关控制一个灯.我们在编写代码的时候并不能准确的知道开关的状态,也就无法确定灯的状态.所有我们只能在开关状态发生改变的时候,获取开关的状态且根据开关的状态对灯的状态进行改变. 这时

关于使用PHP socket.io 做消息推送服务

1.确保已安装redis拓展,可使用php -v 进行查看.如没有安装拓展请参考linux下安装redis扩展. 2.下载文档 https://github.com/Lijianeng10/socket- 3.具体使用方法参考官方文档 https://github.com/walkor/phpsocket.io/tree/master/docs/zh 4.$sender_io = new SocketIO(2120); 此种声明方式需在SocketIO.php 文件中设置IP地址. 表示开启了服

Socket开发

Socket开发框架之消息的回调处理 伍华聪 2016-03-31 20:16 阅读:152 评论:0 Socket开发框架之数据加密及完整性检查 伍华聪 2016-03-29 22:39 阅读:709 评论:2 Socket开发框架之数据传输协议 伍华聪 2016-03-26 00:00 阅读:1049 评论:1 Socket开发框架之框架设计及分析 伍华聪 2016-03-22 11:15 阅读:1931 评论:6 Socket开发框架之数据采集客户端 伍华聪 2011-06-08 23:4

分享一个分布式消息总线,基于.NET Socket Tcp的发布-订阅框架,附代码下载

一.分布式消息总线 在很多MIS项目之中都有这样的需求,需要一个及时.高效的的通知机制,即比如当使用者A完成了任务X,就需要立即告知使用者B任务X已经完成,在通常的情况下,开发人中都是在使用者B所使用的程序之中写数据库轮循代码,这样就会产品一个很严重的两个问题,第一个问题是延迟,轮循机制要定时执行,必须会引起延迟,第二个问题是数据库压力过大,当进行高频度的轮循会生产大量的数据库查询,并且如果有大量的使用者进行轮循,那数据库的压力就更大了. 那么在这个时间,就需要一套能支持发布-订阅模式的分布式消

C# Socket基础(二) 之 服务器异步接收消息

ManualResetEvent reviceManager = new ManualResetEvent(false); 1 public void args_Completed(object sender, SocketAsyncEventArgs e) 2 { 3 //监听完成客户端的请求,一但监听到返回新的套接字 4 var clientSocket = e.AcceptSocket; 5 //启动线程获取客户端发来的消息 6 if (clientSocket == null) retu