程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> Socket開發框架之消息的回調處理,socket開發框架回調

Socket開發框架之消息的回調處理,socket開發框架回調

編輯:C#入門知識

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應用裡面處理回調函數的實現過程,這樣處理可以很好利用回調代碼來封裝處理的細節,對於理解相關的應答操作也是很直觀的。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved