基于Netty的TCP服务框架
19年写的一个基础的TCP服务框架,内置了一个简单IOC容器,当时的目标是一方面能作为组件供第三方集成实现TCP通讯相关功能,另一方面作为提供一种服务框架范式。所以框架核心点主要还是通过适度的封装,隐藏底层的通讯细节,最终调用者接受到的是经过合包分包处理的字节数组,不涉及具体的协议解析,大家如果使用可以再基于业务进行适度的封装。
好,废话不多说,简单介绍下整个架构和源码细节。
Jtcp-cmmon
Jtcp-cmmon主要放置一些基础配置与工具类。 1、这里注意的服务配置类与默认配置项 JtcpConfig、JtcpOptions,JtcpConfig 顾名思义就是配置类,而JtcpOptions则定义了默认值; 2、RouteEnum枚举中列出了几种通用的网络通讯事件类型,作为注解中的字段定义路由
public enum RouteEnum {
OnConnect, //链接
OnDisconnect, //链接断开
OnRecevie, //数据接收
OnSessionTimeOut, //超时
OnException //异常
}
Jtcp-transport
Jtcp-transport 基于Netty提供了TCP服务与报文解析功能,这里我针对常规固定字节起始的协议,通过递归方式对报文粘包、半包等进行了处理
/**
* state = 0 开始解析
* state = 1 解析(递归处理粘包)
* state = 2 半包
*/
private void parseCompletePackets(ChannelHandlerContext ctx, byte[] bytesReady, List<Object> out,
int magicByteBegin, int magicByteEnd) throws IOException {
if (state == 0) { // 开始解析
dataStream = new ByteArrayOutputStream();
// 包数据开始状态,查找开始标识
if (bytesReady[0] != magicByteBegin) {//第一包必须从协议报文头开始
return;
}
state = 1;
}
if (state > 0) {
int pos = indexOfMagicByte(bytesReady, magicByteEnd);//寻找尾部标识index,跳过头部标识位从1开始
if(state == 2) {//半包状态
if(bytesReady[0] == magicByteEnd) {//半包状态,但下段报文7E开头,明显是不正常的
dataStream.reset(); //只能清除目前已累积的所有数据
}
}
if (pos != -1) {
// 结束标识
dataStream.write(bytesReady, 0, pos);
byte[] ad = dataStream.toByteArray();
// 读取完整一个报文
out.add(ad);
// 重置为包开始处理状态
state = 0;
// 将剩余字节写入内存字节流中
if (pos != bytesReady.length) {
byte[] remainBytes = new byte[bytesReady.length - pos];
System.arraycopy(bytesReady, pos, remainBytes, 0, remainBytes.length);
parseCompletePackets(ctx, remainBytes, out, magicByteBegin, magicByteEnd);
}
} else {
// 无结束标识,非完成报文,继续后续处理
state = 2; //报文体读取状态,直接将当前数据写内存字节流中
// 在下一次数据过来时处理结束标识
dataStream.write(bytesReady, 0, bytesReady.length);
}
}
}
Jtcp-core
自定义实现一个IOC容器,可对消息处理handler进行管理,并通过注解的方式制定消息转发机制 首先遍历main函数下所有class类,并缓存所有指定注解@JtcpComponet的class类对象并注入sproutBeanFactory实例工厂
/**
* 缓存所有指定注解的class<?>类对象
* @param packageName
* @return
* @throws Exception
*/
public static Map<String, Class<?>> getBean(String packageName) throws Exception {
if (componetMap == null) {
Set<Class<?>> clsList = getClasses(packageName);
if (clsList == null || clsList.isEmpty()) {
return componetMap;
}
componetMap = new HashMap<>(16);
for (Class<?> cls : clsList) {
Annotation annotation = cls.getAnnotation(JtcpComponet.class);
if (annotation == null) {
continue;
}
JtcpComponet sproutComponet = (JtcpComponet) annotation;
componetMap.put(sproutComponet.value() == null ? cls.getName() : sproutComponet.value(), cls);
}
}
return componetMap;
}
实现方法路由,通过@JtcpRoute并结合上面定义链接、断开、消息接收、超时、异常等事件枚举类型,把触发的网络通信事件转发至指定的业务方法中处理
/**
* 根据注解调用方法
* @param method
* @param annotation
* @param args
* @throws Exception
*/
public void invoke(RouteEnum routeEnum, Object[] args) throws Exception {
Method method = RouterScanner.getInstance().routeMethod(routeEnum);
if (method == null) {
return;
}
Object bean = applicationContext.getBean(method.getDeclaringClass().getName());
if (args == null) {
method.invoke(bean);
} else {
method.invoke(bean, args);
}
}
channelRead接收数据并转发
/**
* 接收消息事件
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object source) {
try {
byte[] dataBytes = (byte[]) source;
JtcpContext sproutContext = new JtcpContext(ctx, dataBytes);
RouteMethod.getInstance().invoke(RouteEnum.OnRecevie, new Object[] { sproutContext });
} catch (Exception ex) {
}
}
Jtcp-example
示例代码
public static void main(String[] args) throws Exception {
JtcpBootstrap bootstrap = new JtcpBootstrap();
bootstrap.config().setHost("127.0.0.1");
bootstrap.config().setPort(8030);
bootstrap.start();
}
@JtcpComponet
public class DemoHandler{
@JtcpRoute(RouteEnum.OnRecevie)
public void res(JtcpContext jtcpContext) {
jtcpContext.context.writeAndFlush(jtcpContext.getRecvBytes());
//System.err.println(BytesUtils.toHexString(context.getRecvBytes()));
}
@JtcpRoute(RouteEnum.OnConnect)
public void onConnect(JtcpContext context ) {
System.err.println("连接成功");
}
}
好的以上就是框架代码的基本构造,涉及到了Netty的应用、粘包半包处理,实例缓存与方法路由等内容,整体并不复杂,这里只是提供了一种服务端编码的思路,供初学者参考。
github地址:https://github.com/dafanjoy/jtcp
基于Netty的TCP服务框架的更多相关文章
- 微言Netty:分布式服务框架
1. 前言 几年前,我就一直想着要设计一款自己的实时通讯框架,于是出来了TinySocket,她是基于微软的SocketAsyncEventArgs来实现的,由于此类提供的功能很简洁,所以当时自己实现 ...
- 基于thrift的微服务框架
前一阵开源过一个基于spring-boot的rest微服务框架,今天再来一篇基于thrift的微服务加框,thrift是啥就不多了,大家自行百度或参考我之前介绍thrift的文章, thrift不仅支 ...
- 基于.NET CORE微服务框架 -surging的介绍和简单示例 (开源)
一.前言 至今为止编程开发已经11个年头,从 VB6.0,ASP时代到ASP.NET再到MVC, 从中见证了.NET技术发展,从无畏无知的懵懂少年,到现在的中年大叔,从中的酸甜苦辣也只有本人自知.随着 ...
- 基于netty的微服务架构
基于netty的微服务架构 微服务一篇好文章 http://san-yun.iteye.com/blog/1693759 教程 http://udn.yyuap.com/doc/essential-n ...
- 基于netty的socket服务端触发了channelInactive方法,但实际连接没有断开的问题
背景: 一个中小型H5游戏,后端使用基于 netty 的socket服务 服务端 分为 分发服务器 & 业务服务器,业务服务器可负载 用户客户端与分发服务器连接 分发服务器再作为客户端与每台业 ...
- 基于Spring-Cloud的微服务框架设计
基于Spring-Cloud的微服务框架设计 先进行大的整体的框架整理,然后在针对每一项进行具体的详细介绍
- 如何基于gRPC沟通微服务框架
本文我们来讲解一下如何使用 gRPC构建微服务,gRPC是一个开源框架,可用于构建可扩展且高性能的微服务并创建服务之间的通信. 背景 随着企业越来越多地转向微服务,对构建这些微服务的低延迟和可扩展框架 ...
- 基于.NET CORE微服务框架 -浅析如何使用surging
1.前言 surging受到大家这么强烈的关注,我感到非常意外,比如有同僚在公司的分享会上分享surging, 还有在博客拿其它的RPC框架,微服务做对比等等,这些举动都让我感觉压力很大,毕竟作为个人 ...
- 基于netty手写RPC框架
代码目录结构 rpc-common存放公共类 rpc-interface为rpc调用方需要调用的接口 rpc-register提供服务的注册与发现 rpc-client为rpc调用方底层实现 rpc- ...
随机推荐
- 【AcWing】第 62 场周赛 【2022.07.30】
AcWing 4500. 三个元素 题目描述 给定一个长度为 \(n\) 的数组 \(r\_1,r\_2,-,r\_n\). 请你找到其中的三个元素 \(r\_a,r\_b,r\_c\),使得 \(r ...
- 技术分享 | 浅谈mysql语法解析调试方法
欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 本文向您介绍一种利用mysql解析器和bison的调试选项进行sql语法解析跟踪 ...
- Vim基础用法,最常用、最实用的命令介绍(保姆级教程)
配置文件设置 set number (设置行号) set nocompatible (设置不兼容vi模式,不设置会导致许多vim特性被禁用) set clipboard=unnamed (设置普通的复 ...
- 使用fontforge修改字体,只保留数字
设计图上的数字采用了Roboto字体,原字体文件200多k,而小程序主包最大2m,承受不起这么大的字体.因为只用到了数字,所以可以使用fontforge编辑字体,删除多余的部分. 一.下载并安装fon ...
- 解决国内不能访问github的问题
问题 最近访问GitHub总是不稳定,经常连不上, 出各种错误(OpenSSL SSL_read: Connection was reset, errno 10054, Connection refu ...
- BZOJ4337 树的同构 (树哈希)(未完成)
样例迷,没过 交了30pts #include <cstdio> #include <iostream> #include <cstring> #include & ...
- 一文搞懂│mysql 中的备份恢复、分区分表、主从复制、读写分离
目录 mysql 的备份和恢复 mysql 的分区分表 mysql 的主从复制读写分离 mysql 的备份和恢复 创建备份管理员 创建备份管理员,并授予管理员相应的权限 备份所需权限:select,r ...
- java-servlet-转发AND路径
转发: a) 什么是转发?一个web组件将未完成的任务交给另一个web组件继续做.通常是一个servlet将数据获取之后转交给jsp进行展现.注:web组件值得是servlet或者jsp b) 如何转 ...
- Taurus.MVC 微服务框架 入门开发教程:项目集成:4、默认安全认证与自定义安全认证。
系列目录: 本系列分为项目集成.项目部署.架构演进三个方向,后续会根据情况调整文章目录. 本系列第一篇:Taurus.MVC V3.0.3 微服务开源框架发布:让.NET 架构在大并发的演进过程更简单 ...
- 尝试理解Linux容器进程与宿主机共享内核到底是什么意思?
背景 近期接触容器技术时,经常看到各类比较容器与虚拟机区别的文章中会提到:容器是共享宿主机的内核,而虚拟机则是拥有自己独立的内核,所以不可能在Linux上用容器运行windows,但是用虚拟机则可以. ...