在一般的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 == )
{
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, );
}
}
});
}
});
}

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

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

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

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

    在前面两篇介绍了Socket框架的设计思路以及数据传输方面的内容,整个框架的设计指导原则就是易于使用及安全性较好,可以用来从客户端到服务端的数据安全传输,那么实现这个目标就需要设计好消息的传输和数据加 ...

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

    我在前面一篇随笔<Socket开发框架之框架设计及分析>中,介绍了整个Socket开发框架的总体思路,对各个层次的基类进行了一些总结和抽象,已达到重用.简化代码的目的.本篇继续分析其中重要 ...

  3. C#的Socket简单实现消息发送

    Socket一般用于网络之间的通信,在这里,实现的是服务端与客户端的简单消息通信.首先是客户端的搭建,一般步骤是先建立Socket绑定本地的IP和端口,并对远端连接进行连接进行监听,这里的监听一般开启 ...

  4. java版Web Socket,实现消息推送

    # web socket是什么? WebSocket协议是基于TCP的一种新的网络协议. 它实现了浏览器与服务器全双工(full-duplex)通信,允许服务器主动发送信息给客户端. ## 用途 实时 ...

  5. C# Socket异步实现消息发送--附带源码

    前言 看了一百遍,不如动手写一遍. Socket这块使用不是特别熟悉,之前实现是公司有对应源码改改能用. 但是不理解实现的过程和步骤,然后最近有时间自己写个demo实现看看,熟悉熟悉Socket. 网 ...

  6. 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_ ...

  7. Java开发笔记(一百一十四)利用Socket传输文本消息

    前面介绍了HTTP协议的网络通信,包括接口调用.文件下载和文件上传,这些功能固然已经覆盖了常见的联网操作,可是HTTP协议拥有专门的通信规则,这些规则一方面有利于维持正常的数据交互,另一方面不可避免地 ...

  8. 电信NBIOT平台的CA证书上传-消息订阅回调地址检测503错误

    在NBIOT北向开发过程中,遇到消息订阅回调地址检测503错误,经过论坛查询与文档查阅一直都没有解决问题,大多人都说是RESTful地址格式问题,但其实不是.最终发现是我们在电信平台创建应用时,上传C ...

  9. 利用socket.io实现消息实时推送

    最近在写的项目中存在着社交模块,需要实现这样的一个功能:当发生了用户被点赞.评论.关注等操作时,需要由服务器向用户实时地推送一条消息.最终完成的项目地址为:socket-message-push,这里 ...

随机推荐

  1. windows10的激活及SQL Server 2008 的安装

    在我第一次安装的SQL Server的时候,由于我的电脑是windows8专业版未激活的系统,当时安装的时候,首先出现提示说我电脑缺少了某一个插件,于是乎就下了安装.但是后来又是安装不上,各种问题一一 ...

  2. 项目开发之使用 maven

    本文将详述 maven 在软件项目中的使用.首先讲述 maven 的基本工作原理及环境的搭建.然后讲述开发及配置管理人员如何使用 maven,最后将介绍 maven 与 eclipse 集成使用. m ...

  3. Unity3D使用经验总结 缺点篇

    不论是从官方手册,还是各种第三方教程,几乎涉及到的,都是讲如何使用U3D,以及U3D的优点. 虽然我是用的一个让步语气,但请不要否认U3D的这些优点,它们的确存在. 但对于一个引擎的特性来说,优点与缺 ...

  4. 为 Exchange 服务器编写自定义的反垃圾插件

    Exchange 2010 的 Edge Transport 包含了一些 Anti-spam 的 Feature,如图: 都开启了,但是呢,还是会有漏网之鱼,而且把这些邮件自己列为 Junk 也起不了 ...

  5. synchronized同步对象锁

    package com.system.util; import com.common.Constants; import com.util.Cache; /** * 创建同步对象锁 * * @auth ...

  6. 上学时的HTML+JS+CSS(小总结)

    html:超文本标记语言 基本标签: { 文本标签:<pre></pre>:原封不动的保留空白区域.      <br />:换行.      <hr wid ...

  7. redis数据结构整理(二)

    摘要: 1.各个数据结构的应用举例 1.1 String类型应用举例 1.2List类型应用举例 1.3Set类型应用举例 1.4Sorted Set类型应用举例 1.5Hash类型应用举例 内容: ...

  8. 在Windows下安装Memcached

    Windows下的Memcache安装: 需要运行命令行工具cmd 请以管理员权限运行 开始->附件->命令提示符,以管理员身份运行 假如当前C:\windows\system32,输入c ...

  9. lua的table表处理 及注意事项

    lua,一款很轻量级很nice很强大的脚本语言,做为lua中使用最为频繁的table表,在使用之时还是有颇多的好处与坑的: 下面是大牛 云风的一片关于lua table的blog,可使得对lua ta ...

  10. Drupal网站开发实践--自定义购物流程

    由于Commerce模块自带的购物流程步骤过多,界面不太美观,所以需要重新设计. 改造后的购物流程分成两部:购物车->结算,就两个页面.购物车页面可以修改商品的数量,删除购物车内商品,查看总金额 ...