Mina Tcp服务器开发
因项目架构需求,需要开发一个Mina Tcp服务器。我的Mina服务器是Java winForm,这与在web项目使用会有少许不同。
1、Maven依赖
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>2.2.1</version>
</dependency>
2、开发网络数据包编/解码器(传输文本消息可以配置mina使用TextLineCodeFactory工厂类获取编/解码器),用于socket传输数据的过滤处理。本次开发Tcp服务器传输的是字节数据,并且自定义了通信的协议;所以编写了下面的编解码器及工厂类:
//解码器,用于解包socket接收的数据
public class TcpByteDecoder extends CumulativeProtocolDecoder {
/**
* 固定包头长度
*/
private static final int Package_Header_Length = 6; @Override
protected boolean doDecode(IoSession ioSession, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
if (Package_Header_Length < in.remaining()) { //缓冲区中的数据长度大于包头,说明可以尝试解码
//标记当前position,以便后继的reset操作能恢复position位置
in.mark();
//获取协议头的5、6字节对应的剩余包长度(协议格式固定为5、6字节存储的是一包数据后续剩余字节数量)
int len = in.getUnsignedShort(4);
if ((Package_Header_Length + len) > in.remaining()) {
//包头长度+包头内指明的后续字节长度>接收数据缓冲区数据长度,则说明接收数据缓冲区的数据还不够一包数据。重置position到操作前,继续接收数据
in.reset();
return false;
}
//创建byte数组,接收一包数据。一包数据的长度=包头字节数+包字节剩余字节数
byte[] msg = new byte[Package_Header_Length + len];
//获取缓冲区中的数据到数据包byte数组中
in.get(msg);
//将数据包byte数组输出后续过滤器或处理器
out.write(msg);
//读取包后,如果缓冲区还有数据且>包头
if (Package_Header_Length < in.remaining()) {
//返回ture,再次进行解包
return true;
}
}
return false;//返回false继续接收数据
}
}
//编码器,用于编码要发送出去的数据(程序上层应用数据格式为byte[],此处只将byte[]原样输出)
public class TcpByteEncoder extends ProtocolEncoderAdapter { @Override
public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {
byte[] data = (byte[])message;//获取要发送的数据
IoBuffer buf = IoBuffer.allocate(data.length).setAutoExpand(true);//准备一个大小与数据长度一样的输出缓冲区
buf.put(data);//将数据放入缓冲区
buf.flip();//固定数据
out.write(buf);//将缓冲区内容输出
}
}
//编解码器工厂
public class TcpProtocolCodecFactory implements ProtocolCodecFactory {
private TcpByteDecoder decoder;
private TcpByteEncoder encoder; public ModbusTcpProtocolCodecFactory() {
decoder = new TcpByteDecoder();
encoder = new TcpByteEncoder();
} @Override
public ProtocolEncoder getEncoder(IoSession ioSession) throws Exception {
return encoder;
} @Override
public ProtocolDecoder getDecoder(IoSession ioSession) throws Exception {
return decoder;
}
}
3、开发Mina事件处理程序
public class MinaClientHandler extends IoHandlerAdapter {
private String deviceNo;
public MinaClientHandler(String deviceNo) {
this.deviceNo = deviceNo;
}
@Override
public void sessionCreated(IoSession session) throws Exception {
super.sessionCreated(session);
}
@Override
public void sessionOpened(IoSession session) throws Exception {
super.sessionOpened(session);
}
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
if (session.isConnected()) {
session.closeNow();
}
super.exceptionCaught(session, cause);
}
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
//此处获取到的message,实际就是在上述解码器中out.write的内容
byte[] data = (byte[])message;
//原样输出给客户端
session.write(message);
}
@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
super.sessionIdle(session, status);
}
}
4、Mina Server
//这里要开启多个server,只开启一个server的情况需要修改下面的代码
public class MinaService { public boolean startMinaServer(Integer port) {
// 1. 创建IoAcceptor
IoAcceptor acceptor = new NioSocketAcceptor();
// 2. 加入日志记录过滤器,用SL4J库记录信息
acceptor.getFilterChain().addLast("logger", new LoggingFilter());
// 3. 加入编码过滤器,用于解码所有收到的信息,使用 new TextLineCodecFactory() r
// 发送的信息进行编码,返回是MINA自带的,功能有限,只能处理文本戒者String类型。
acceptor.getFilterChain().addLast("socketFilter", new ProtocolCodecFilter(new TcpProtocolCodecFactory()));
// 4. 设置ServerHandler, 自定义的Handler,TimeServerHandler
acceptor.setHandler(new MinaClientHandler());
// 5. 设置空闲时间, 这里的BOTH_IDLE指EADER_IDLE和WRITER_IDLE都为120秒
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 120);
// 6. 绑定监听端口.
try {
acceptor.bind(new InetSocketAddress(port));
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
}
5、使用Telnet进行测试(本Server因为只处理特定协议的byte[]数据,因此不能直接使用telnet测试)
telnet ip 端口
6、特别注意:尽量把日志系统配置好并开启,可以快速定位错误并有助于跟踪服务的运行。
Mina Tcp服务器开发的更多相关文章
- 机动车驾驶员计时培训系统符合性检测平台TCP服务器设计和开发
驾校计时平台的TCP服务器,主要用于接入计时终端,计时终端与计时平台.计时平台与省级监管服务平台.省级监管服务平台与全国驾培平台的卫星定位过程明细数据和学时过程明细数据接口应使用基于JT/T 808标 ...
- Mina、Netty、Twisted一起学(一):实现简单的TCP服务器
MINA.Netty.Twisted为什么放在一起学习?首先,不妨先分别看一下它们官方网站对其的介绍: MINA: Apache MINA is a network application frame ...
- 【Andorid开发框架学习】之Mina开发之服务器开发
下午那篇博客我们讲到了Mina的客户端的开发,如果还有没看过的同学可以看一下,我是传送门.现在,我们来学习一下,Mina的服务器的开发. 一.首先看一下,我的服务器的代码图片: 服务器代码我是在My ...
- <摘录>详谈高性能TCP服务器的开发
对于开发一款高性能服务器程序,广大服务器开发人员在一直为之奋斗和努力.其中一个影响服务器的重要瓶颈就是服务器的网络处理模块.如果一款服务器程序不能及时的处理用户的数据.则服务器的上层业务逻辑再高效也是 ...
- 16-ESP8266 SDK开发基础入门篇--TCP 服务器 非RTOS运行版,串口透传(串口回调函数处理版)
https://www.cnblogs.com/yangfengwu/p/11105466.html 其实官方给的RTOS的版本就是在原先非RTOS版本上增加的 https://www.cnblogs ...
- LwIP应用开发笔记之五:LwIP无操作系统TCP服务器
前面我们实现了UDP服务器及客户端以及基于其上的TFTP应用服务器.接下来我们将实现同样广泛应用的TCP协议各类应用. 1.TCP简述 TCP(Transmission Control Protoco ...
- 18-ESP8266 SDK开发基础入门篇--TCP 服务器 RTOS版,串口透传,TCP客户端控制LED
https://www.cnblogs.com/yangfengwu/p/11112015.html 先规定一下协议 aa 55 02 01 F1 4C 控制LED点亮 F1 4C为CRC高位和低位 ...
- 17-ESP8266 SDK开发基础入门篇--TCP服务器 RTOS版,小试牛刀
https://www.cnblogs.com/yangfengwu/p/11105466.html 现在开始写... lwip即可以用socket 的API 也可以用 netconn 的API实 ...
- 基于MINA框架快速开发网络应用程序
1.MINA框架简介 MINA(Multipurpose Infrastructure for Network Applications)是用于开发高性能和高可用性的网络应用程序的基础框架.通过使用M ...
- socket服务器开发中的SO_REUSEADDR选项与让人心烦的TIME_WAIT
1 发现问题 我在开发一个socket服务器程序并反复调试的时候,发现了一个让人无比心烦的情况:每次kill掉该服务器进程并重新启动的时候,都会出现bind错误:error:98,Address al ...
随机推荐
- 2023-11-18:用go语言,如果一个正方形矩阵上下对称并且左右对称,对称的意思是互为镜像, 那么称这个正方形矩阵叫做神奇矩阵。 比如 : 1 5 5 1 6 3 3 6 6 3 3 6 1 5
2023-11-18:用go语言,如果一个正方形矩阵上下对称并且左右对称,对称的意思是互为镜像, 那么称这个正方形矩阵叫做神奇矩阵. 比如 : 1 5 5 1 6 3 3 6 6 3 3 6 1 5 ...
- js做四则运算时,精度丢失问题及解决方法
一.前言:这个问题可以说是程序员必踩的坑,因此网上针对该问题的分析有很多也很详细,解决方法也比较统一,写法也是大同小异,本以为预期效果真能如他们所说是完美的,然而效果却是差强人意. 二.问题:首先,先 ...
- 总结(5)--- Numpy和Pandas库常用函数
二.常用库 1.NumPy NumPy是高性能科学计算和数据分析的基础包.部分功能如下: ndarray, 具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组. 用于对整组数据进行快速运算的标准 ...
- Flask 使用Jinja2模板引擎
Jinja2,由Flask框架的创作者开发,是一款功能丰富的模板引擎,以其完整的Unicode支持.灵活性.高效性和安全性而备受推崇.最初受Django模板引擎启发,Jinja2为Flask提供了强大 ...
- 在模态窗口中控制窗口的隐藏和显示(.NET)
如果你创建了模态窗口,虽然一些API,例如Editor.GetSelection(),可以自动隐藏模式对话框,但如果从模态窗口出发与编辑器(编辑器指的模型空间,即你绘图的窗口)交互, 它会在GetSe ...
- 聊一聊Rust的enum
enum在实际编程中是非常常用的,enum的目的就是为了清晰定义出散落在系统各个角落的相同概念的有限固定值. 一.enum介绍如果是简单定义固定值,我们可以使用常量const.比如 public co ...
- 牛客小白月赛2 E题 是是非非 (尼姆博弈)
题目链接:https://www.nowcoder.com/acm/contest/86/E 解题思路:由尼姆博弈我们可以知道,如果所有堆的石子数量异或为0,那么先手必败,否则先手必胜. 由异或我们可 ...
- C++ Qt开发:QSqlDatabase数据库组件
Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍QSqlDat ...
- 【笔记】springSecurity-OAuth2.0-授权模式演示
SpringSecurityOauth2架构 介绍 流程: 用户访问,此时没有Token.Oauth2RestTemplate会报错,这个报错信息会被Oauth2ClientContextFilter ...
- OpenFeign:Spring Cloud声明式服务调用组件
OpenFeign:Spring Cloud声明式服务调用组件 问题总结 OpenFeign? Feign VS OpenFeign? OpenFeign实现远程服务调用? OpenFeign超时控制 ...