zoukankan      html  css  js  c++  java
  • 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应用里面处理回调函数的实现过程,这样处理可以很好利用回调代码来封装处理的细节,对于理解相关的应答操作也是很直观的。

  • 相关阅读:
    bridge桥接模式
    docker部署mysql实现远程访问
    翻下旧资料,发现96年考过foxbase二级
    这几年专注于流程管理与RPA落地
    201521123080《Java程序设计》第10周学习总结
    201521123034《Java程序设计》第十周学习总结
    Beta版本冲刺计划及安排
    团队作业7——Alpha冲刺之事后诸葛亮
    团队作业6——展示博客(Alpha版本)
    团队作业4——第一次项目冲刺(Alpha版本)第一天+第二天+第三天+第四天+第五天+第六天+第七天
  • 原文地址:https://www.cnblogs.com/zxtceq/p/5417466.html
Copyright © 2011-2022 走看看