mina.net 梳理
LZ最近离职,闲着也是闲着,打算梳理下
公司做的是电商,CTO打算把2.0系统用java 语言开发,LZ目前不打算做java,所以 选择离职。离职前,在公司负责的最后一个项目 供应链系统。
系统分为 3套子系统:
1 供应链工作平台(即用户操作平台):采用CS架构,Sqlite做缓存。
2 消息中心: 后台程序,采用mina.net,scoket 长连接 保证服务消息的 推送,后台消息的提醒,和 系统对最新订单的缓存。
3 WindowsService 监控消息中心,保证消息中心 随系统的开启而启动
mina 简介:
Apache Mina Server 是一个网络通信应用框架,它主要是对基于TCP/IP、UDP/IP协议栈的通信框架,Mina 可以帮助我们快速开发高性能、高扩展性的网络通信应用,Mina 提供了事件驱动、异步(Mina 的异步IO 默认使用的是JavaNIO 作为底层支持)操作的编程模型。
mina.net 是Apache Mina Server 的.net 版本 主要用于系统的长连接通信
安装:
PM> Install-Package Mina
mina.net 主要对象:
1.AsyncSocketConnector: 发起链接
2.IoSession:mina 链接创建成功之后 客户端,服务的的数据传送
3.IoHandlerAdapter:适配器类。可以扩展
4.DemuxingProtocolCodecFactory:构建协议编码工厂
适配器主要方法:
1 MessageReceived:收到消息时触发
2.MessageSent 发送消息后触发
3.SessionClosed 关闭Session时 触发
4.SessionCreated 创建Session时 触发
5.ExceptionCaught 发生异常时 触发
6.SessionIdleSession 空闲时 触发
实现思路:
创建mina链接:
public void StartProcess(LoginContext config)
{
AsyncSocketConnector connector = new Mina.Transport.Socket.AsyncSocketConnector();
//注册协议编解码器工厂
connector.FilterChain.AddLast("encoding", new ProtocolCodecFilter(new MyMinaCodecFactory()));
//指定服务端IP 和端口号
connector.DefaultRemoteEndPoint = new IPEndPoint(IPAddress.Parse(MinaConfig.Ip), MinaConfig.Port);
//初始化 消息处理类
var headerDic = CreateHeader();
//继承IoHandlerAdapter构建适配器
MinaMessageHandler headler = new MinaMessageHandler(config, connector, headerDic); connector.Handler = headler; while (true)
{
try
{
//ClientHandler
//建立链接
session = connector.Connect().Await().Session;
break;
}
catch (Exception ex)
{
_Log.Error(ex.Message, ex);
Thread.Sleep(1000);
} }
}
链接建立成功之后,触发mina.net 内部机制的SessionCreated 方法,登录用户
public override void SessionCreated(Mina.Core.Session.IoSession session)
{
try
{
MyBaseMessage message = new LoginRequestMessage(ClientConfig.ClientAddr,ClientConfig.SharedSecret);
(message as LoginRequestMessage).SetAutherString();
session.Write(message);
}
catch (Exception ex)
{
_Log.Error(ex.Message, ex);
}
finally
{
base.SessionCreated(session);
}
}
重写MessageReceived方法,收到服务器消息之后,处理相应事件
/// <summary>
/// 收到消息时 触发--处理消息,给服务器发送处理结果
/// </summary>
/// <param name="session"></param>
/// <param name="message"></param>
public override void MessageReceived(Mina.Core.Session.IoSession session, object message)
{
try
{
if (message is MyBaseMessage)
{
var m = message as MyBaseMessage; if (HeaderDic.Keys.Any(p=>p==m.GetCommandType()))
{
var messageHeader = HeaderDic[m.GetCommandType()]; messageHeader.Handle(session,m);
} }
}
catch (Exception ex)
{
_Log.Error(ex.Message, ex);
}
finally
{
base.MessageReceived(session, message);
} }
重写 SessionClosed 事件,关闭session时,通知服务器,客户端已关闭链接
/// <summary>
/// 关闭Session时 触发-发送关闭消息
/// </summary>
/// <param name="session"></param>
public override void SessionClosed(Mina.Core.Session.IoSession session)
{
try
{
while (true)
{
try
{
if (Connector != null)
{
if (!Connector.Disposed)
{
session = Connector.Connect().Await().Session; break;
}
else
{
break;
}
}
}
catch (Exception ex)
{
Thread.Sleep(1000);
}
}
}
catch (Exception ex)
{
_Log.Error(ex.Message, ex);
}
finally
{
base.SessionClosed(session);
}
}
重写 ExceptionCaught 方法,发生异常时,关闭链接
/// <summary>
/// 发生异常时 触发,关闭session 重新登录
/// </summary>
/// <param name="session"></param>
/// <param name="cause"></param>
public override void ExceptionCaught(Mina.Core.Session.IoSession session, Exception cause)
{
try
{
session.Close(true);
_Log.Error(cause.Message, cause);
}
catch (Exception ex)
{
_Log.Error(ex.Message, ex);
}
finally
{
base.ExceptionCaught(session, cause);
}
}
重写 SessionIdle 方法,session空闲时,测试心跳
/// <summary>
/// Session 空闲时 发生
/// </summary>
/// <param name="session"></param>
/// <param name="status"></param>
public override void SessionIdle(Mina.Core.Session.IoSession session, Mina.Core.Session.IdleStatus status)
{
try
{
MyBaseMessage message = new DetectionMessage(); session.Write(message);
}
catch (Exception ex)
{
_Log.Error(ex.Message, ex);
}
finally
{
base.SessionIdle(session, status);
}
}
构建协议编解码器工厂
public class MyMinaCodecFactory : DemuxingProtocolCodecFactory
{
public MyMinaCodecFactory()
{
AddMessageEncoder(new MyMinaEncoder());
AddMessageDecoder(new MyMinaDecoder());
}
}
编码器工厂,将对象 序列号成 bytes 数据
public class MyMinaEncoder : IMessageEncoder<MyBaseMessage>
{ public void Encode(IoSession session, MyBaseMessage message, IProtocolEncoderOutput output)
{
IoBuffer buf = IoBuffer.Allocate(12);
buf.AutoExpand = true; var messageBytes = message.EncodeMessage(); buf.Put(messageBytes);
buf.Flip(); session.Write(buf); } public void Encode(IoSession session, object message, IProtocolEncoderOutput output)
{
IoBuffer buf = IoBuffer.Allocate(12);
buf.AutoExpand = true; if (message is MyBaseMessage)
{
var m = message as MyBaseMessage; var messageBytes = m.EncodeMessage(); buf.Put(messageBytes);
buf.Flip(); } session.Write(buf); }
}
解码器工厂,将字节转换为对象
public class MyMinaDecoder : IMessageDecoder
{
public ILog _Log = LogManager.GetLogger("MessageHandler"); public MessageDecoderResult Decodable(IoSession session,IoBuffer input)
{
try
{
if (input.Remaining < CommandConfig.messageHeaderLength)
{
return MessageDecoderResult.NeedData;
}
var headerBytes = new byte[CommandConfig.messageHeaderLength];
for (int i = 0; i < CommandConfig.messageHeaderLength; i++)
{
headerBytes[i] = input.Get(i);
} var lengthBytes = new byte[4];
var commandIdBytes = new byte[4];
var sequenceBytes = new byte[4]; Array.Copy(headerBytes, 0, lengthBytes, 0, 4);
Array.Copy(headerBytes, 4, commandIdBytes, 0, 4);
Array.Copy(headerBytes, 8, sequenceBytes, 0, 4); var messageLength = lengthBytes.ByteToUint();//Convert.ToInt32(Encoding.Default.GetString(headerBytes, 0, 4)); var messageCommand = commandIdBytes.ByteToUint();//(uint)Convert.ToInt32(Encoding.Default.GetString(headerBytes, 4, 4)); if (messageCommand==CommandConfig.connect
|| messageCommand == CommandConfig.connectResp
|| messageCommand == CommandConfig.terminate
|| messageCommand == CommandConfig.terminateResp
|| messageCommand == CommandConfig.notify
|| messageCommand == CommandConfig.notifyResp
|| messageCommand == CommandConfig.cmppActiveTest
|| messageCommand == CommandConfig.cmppActiveTestResp)
{
return MessageDecoderResult.OK;
}
return MessageDecoderResult.NotOK; }
catch (Exception ex)
{
_Log.Error(ex.Message, ex);
return MessageDecoderResult.NeedData;
}
}
}
结语:
博客写的不多,不喜勿碰,谢谢
欢迎指点和纠正
mina.net 梳理的更多相关文章
- 【初码干货】在Window Server 2016中使用Web Deploy方式发布.NET Web应用的重新梳理
在学习和工作的过程中,发现很多同事.朋友,在做.NET Web应用发布的时候,依然在走 生成-复制到服务器 这样的方式,稍微高级一点的,就是先发布到本地,再上传到服务器 这种方式不仅效率低下,而且不易 ...
- JAVA通信系列二:mina入门总结
一.学习资料 Mina入门实例(一) http://www.cnblogs.com/juepei/p/3939119.html Mina入门教程(二)----Spring4 集成Mina http:/ ...
- Mina、Netty、Twisted一起学(八):HTTP服务器
HTTP协议应该是目前使用最多的应用层协议了,用浏览器打开一个网站就是使用HTTP协议进行数据传输. HTTP协议也是基于TCP协议,所以也有服务器和客户端.HTTP客户端一般是浏览器,当然还有可能是 ...
- [SQL] SQL 基础知识梳理(一)- 数据库与 SQL
SQL 基础知识梳理(一)- 数据库与 SQL [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5902856.html 目录 What's 数据库 ...
- [SQL] SQL 基础知识梳理(二) - 查询基础
SQL 基础知识梳理(二) - 查询基础 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5904824.html 序 这是<SQL 基础知识梳理( ...
- [SQL] SQL 基础知识梳理(三) - 聚合和排序
SQL 基础知识梳理(三) - 聚合和排序 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5926689.html 序 这是<SQL 基础知识梳理 ...
- [SQL] SQL 基础知识梳理(四) - 数据更新
SQL 基础知识梳理(四) - 数据更新 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5929786.html 序 这是<SQL 基础知识梳理( ...
- [SQL] SQL 基础知识梳理(五) - 复杂查询
SQL 基础知识梳理(五) - 复杂查询 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5939796.html 序 这是<SQL 基础知识梳理( ...
- 【Spring-web】RestTemplate源码学习——梳理内部实现过程
2016-12-28 by 安静的下雪天 http://www.cnblogs.com/quiet-snowy-day/p/6228198.html 提示:使用手机浏览时请注意,图多费流量. 本篇 ...
随机推荐
- 基于Modbus的C#串口调试开发
说明:本文主要研究的是使用C# WinForm开发的串口调试软件(其中包含Modbus协议相关操作).Modbus相关协议可以查阅百度文库等,可参考: <http://wenku.baidu.c ...
- 前端总结·基础篇·JS(三)arguments、callee、call、apply、bind及函数封装和构造函数
前端总结系列 前端总结·基础篇·CSS(一)布局 前端总结·基础篇·CSS(二)视觉 前端总结·基础篇·CSS(三)补充 前端总结·基础篇·JS(一)原型.原型链.构造函数和字符串(String) 前 ...
- Linux块设备IO子系统(二) _页高速缓存
磁盘驱动就是实现磁盘空间和内存空间数据上的交互,在上一篇中我们讨论了内存端的Page Segment Block Sector相关的概念,本文以3.14内核为例,讨论这部分内存是如何被组织管理的.我们 ...
- C#文件上传类,文件流,字节数组等
using System;using System.IO;using System.Web;using System.Web.UI.WebControls; namespace DotNet.Util ...
- 自适应的tab菜单栏
代码部分: Css代码:*{ margin:0px; padding:0px; font-size:62.5%;}body{ background-color:#FFFFFF;}.zw-test-ti ...
- PMP和PRINCE2的价值各是什么?PRINCE2的含金量如何?PMP和prince2有什么区别?
很多学员朋友会问我同样的问题:"PMP和PRINCE2到底有什么区别?哪个含金量更高?"看来,这是所有要参加认证的朋友普遍关心的问题,我将根据自己的切身体会,从三个方面回答这个问题 ...
- net.sz.framework 框架 轻松搭建服务---让你更专注逻辑功能---初探
前言 在之前的文章中,讲解过 threadmodel,socket tcp ,socket http,log,astart ,scripts: 都是分片讲解,从今天开始,将带大家,一窥 net.sz. ...
- STM32驱动OV7725摄像头颜色识别
实验目的: 使用stm32驱动OV7725摄像头进行图像实时采集,在tft屏幕上实时显示并识别图像中的特定颜色,在颜色的周围画上框. 实验现象: 我的工程代码链接: http://download.c ...
- python爬虫实战(二)--------千图网高清图
相关代码已经修改调试----2017-3-21 实现:千图网上高清图片的爬取 程序运行20小时,爬取大约162000张图片,一共49G,存入百度云.链接:http://pan.baidu.com/s/ ...
- VB6/VBA中跟踪鼠标移出窗体控件事件(类模块成员函数指针CHooker类应用)
一.关于起因 前几天发了一篇博文,是关于获取VB类模块成员函数指针的内容(http://www.cnblogs.com/alexywt/p/5880993.html):今天我就发一下我的应用实例. V ...