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 == )
{
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开发框架之消息的回调处理的更多相关文章
- Socket开发框架之数据加密及完整性检查
在前面两篇介绍了Socket框架的设计思路以及数据传输方面的内容,整个框架的设计指导原则就是易于使用及安全性较好,可以用来从客户端到服务端的数据安全传输,那么实现这个目标就需要设计好消息的传输和数据加 ...
- Socket开发框架之数据传输协议
我在前面一篇随笔<Socket开发框架之框架设计及分析>中,介绍了整个Socket开发框架的总体思路,对各个层次的基类进行了一些总结和抽象,已达到重用.简化代码的目的.本篇继续分析其中重要 ...
- C#的Socket简单实现消息发送
Socket一般用于网络之间的通信,在这里,实现的是服务端与客户端的简单消息通信.首先是客户端的搭建,一般步骤是先建立Socket绑定本地的IP和端口,并对远端连接进行连接进行监听,这里的监听一般开启 ...
- java版Web Socket,实现消息推送
# web socket是什么? WebSocket协议是基于TCP的一种新的网络协议. 它实现了浏览器与服务器全双工(full-duplex)通信,允许服务器主动发送信息给客户端. ## 用途 实时 ...
- C# Socket异步实现消息发送--附带源码
前言 看了一百遍,不如动手写一遍. Socket这块使用不是特别熟悉,之前实现是公司有对应源码改改能用. 但是不理解实现的过程和步骤,然后最近有时间自己写个demo实现看看,熟悉熟悉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_ ...
- Java开发笔记(一百一十四)利用Socket传输文本消息
前面介绍了HTTP协议的网络通信,包括接口调用.文件下载和文件上传,这些功能固然已经覆盖了常见的联网操作,可是HTTP协议拥有专门的通信规则,这些规则一方面有利于维持正常的数据交互,另一方面不可避免地 ...
- 电信NBIOT平台的CA证书上传-消息订阅回调地址检测503错误
在NBIOT北向开发过程中,遇到消息订阅回调地址检测503错误,经过论坛查询与文档查阅一直都没有解决问题,大多人都说是RESTful地址格式问题,但其实不是.最终发现是我们在电信平台创建应用时,上传C ...
- 利用socket.io实现消息实时推送
最近在写的项目中存在着社交模块,需要实现这样的一个功能:当发生了用户被点赞.评论.关注等操作时,需要由服务器向用户实时地推送一条消息.最终完成的项目地址为:socket-message-push,这里 ...
随机推荐
- ZooKeeper学习第一期---Zookeeper简单介绍
一.分布式协调技术 在给大家介绍ZooKeeper之前先来给大家介绍一种技术——分布式协调技术.那么什么是分布式协调技术?那么我来告诉大家,其实分布式协调技术主要用来解决分布式环境当中多个进程之间的同 ...
- java提高篇(十七)-----异常(二)
承接上篇博文:java提高篇-----异常(一) 五.自定义异常 Java确实给我们提供了非常多的异常,但是异常体系是不可能预见所有的希望加以报告的错误,所以Java允许我们自定义异常来表 ...
- ubuntu git 使用
apt-get install git//ubuntu安装git mkdir -p /var/www/gitProj //创建文件夹 cd /var/www/gitProj //进入文件夹 git i ...
- [51单片机] 以PWM控制直流电机为例建一个简单的51工程框架
目录 1)功能概述 2)引脚连接 3)框架介绍 4)模块说明 5)复用规则 6)工程链接 1)功能概述 名称:独立按键控制直流电机调速 内容:对应的电机接口需用杜邦线连接到uln2003电机控制端; ...
- ActiveMQ第六弹:设置多个并行的消费者
消息队列本来就是一种经典的生产者与消费者模式.生产者向消息队列中发送消息,消费者从消息队列中获取消息来消费. 消息的传送一般由一个代理来实现的,那就是Message broker(即消息代理).Mes ...
- ubuntu:solve the problem of 'E:Problem with MergeList /var/lib/apt/lists/'
just run this command: sudo rm /var/lib/apt/lists/* -vfR it will remove all the software package wit ...
- 302 Moved Temporarily
这个就是表示 重定向!! 不过,302在不同HTTP协议下的状态信息不同. Moved temporarily (redirect) 你所连接的页面进行了Redirect Found 类似于301,但 ...
- tr
参照http://www.cnblogs.com/djcsch2001/archive/2011/05/08/2040255.html tr -options set1 [set2] ---- set ...
- windows批处理总结
rem echo off 表示之后所有命令行不显示,但命令结果总是会显示的!! 不存在%ROOT_DIR% . %CUR_DIR%的变量 rem @表示命令行不显示当前行,但命令结果总是会显示的!! ...
- 每天一个linux命令(54):ping命令
Linux系统的ping命令是常用的网络命令,它通常用来测试与目标主机的连通性,我们经常会说“ping一下某机器,看是不是开着”.不能打开网页时会说“你先ping网关地址192.168.1.1试试”. ...