基于Netty的TCP服务框架

19年写的一个基础的TCP服务框架,内置了一个简单IOC容器,当时的目标是一方面能作为组件供第三方集成实现TCP通讯相关功能,另一方面作为提供一种服务框架范式 。所以框架核心点主要还是通过适度的封装,隐藏底层的通讯细节,最终调用者接受到的是经过合包分包处理的字节数组,不涉及具体的协议解析,大家如果使用可以再基于业务进行适度的封装 。
好,废话不多说,简单介绍下整个架构和源码细节 。
Jtcp-cmmonJtcp-cmmon主要放置一些基础配置与工具类 。1、这里注意的服务配置类与默认配置项 JtcpConfig、JtcpOptions,JtcpConfig 顾名思义就是配置类,而JtcpOptions则定义了默认值; 2、RouteEnum枚举中列出了几种通用的网络通讯事件类型,作为注解中的字段定义路由
    public enum RouteEnum {        OnConnect, //链接        OnDisconnect, //链接断开        OnRecevie, //数据接收        OnSessionTimeOut, //超时        OnException //异常    }Jtcp-transportJtcp-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);            }        }    }

经验总结扩展阅读