netty socket解析自定义数据格式

前提:

当我们设计了一个通信协议后,那么基于TCP的服务端想要准确接收每一个信息会遇到粘包和拆包的问题。

原因:

  • 粘包会导致接收后信息报文解析失败,不完整或者有额外其他包的信息。
  • TCP协议需要粘包拆包是因为TCP协议数据传输没有边界概念,传输数据有限制和网络优化。数据过小发送时间间隔很短时为了提高效率会合并发送数据,数据过大就要拆包多个进行发送,前面数据过大拆的包和后一个数据一起发送了。
  • UDP没有因为有个消息保护边界。

如何识别每一个信息:

  • 定长 发送接收的数据长度固定识别 短了补齐(FixedLengthFrameDecoder
  • 特殊分隔符进行信息识别 回车换行(LineBasedFrameDecoder与DelimiterBasedFrameDecoder
  • 消息长度 可明确读取消息的数据(LengthFieldBasedFrameDecoder与LengthFieldPrepender
  • 自定义随心控制(MessageToByteEncoder和ByteToMessageDecoder
  • 常用的http请求使用了特殊字符+长度

http请求报文格式

  • 1)请求行:以\r\n结束;
  • 2)请求头:以\r\n结束;
  • 3)POST请求 Content-Length: 14 (get没有
  • 4)\r\n;
  • 5)post数据; (get没有

http响应报文格式

  • 1)响应行:以\r\n结束;
  • 2)响应头:以\r\n结束;
  • 3)Content-Length: 14
  • 4)\r\n;
  • 5)数据;

数据传输的方式

  1. 直接socket处理数据 效率和处理各种网络情况。
  2. nio 效率提高了但是复杂搞不好。
  3. 基于nio的netty省事直接业务处理。
  4. 很久前的一个项目原有的数据传输用的socket压测的时候各种情况(丢包响应都不行其他问题)后面改为nio一样,最后用了netty测试搞完不用加班系统还稳定。

下面说下netty的一个tcp的自定义解码拆包demo

  1. 这个例子前6个字节是xml报文长度
  2. 剩下主要是ByteBuf的一些操作,有些位置的处理。
java 复制代码
public class StringLenDecoder extends ByteToMessageDecoder {
	
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws UnsupportedEncodingException {
        // 头部长度6字节,说明消息长度还没满,直接返回
        if (in.readableBytes() < 6){
            return;
        }
        // 设置回滚点
        in.markReaderIndex();
        
        // 消息长度,同时会使readerIndex向前移动6个指针
        byte[] lenBytes = new byte[6];
		in.readBytes(lenBytes);
		String xmlLen=new String(lenBytes);

        //接收报文为空或不为数字
        if(null==xmlLen ||"".equals(xmlLen.trim()) || !xmlLen.matches("^[0-9]{6}$")){
        	in.resetReaderIndex();
			return;
		}
     
        int len=Integer.valueOf(xmlLen);
        
        //"重置读指针,并返回
        if (in.readableBytes() < len){
            in.resetReaderIndex();
            return;
        }
        
        byte msgbytter[]=new byte[len];
        in.readBytes(msgbytter);
       
       //得到报文
        String msg=xmlLen+new String(msgbytter,Charset.forName("GBK"));
        //log
        out.add(msg);
    }
}
相关推荐
再吃一根胡萝卜11 小时前
微服务治理的“四大护法”:从 Django 视角理解 Spring Cloud 核心组件
后端
再吃一根胡萝卜11 小时前
面试终极挑战:如何用 Django 经验,回答 Java 微服务实战问题?
后端
To_OC12 小时前
装完 ESLint 它一声不吭?我还以为代码写得多好
后端·node.js·eslint
凤山老林13 小时前
精细化流量治理:Spring Boot 动态特性开关与灰度发布体系
java·spring boot·后端
vipbic14 小时前
一个前端的 9 天重构:我是怎么用 Codex 重做航栈的
前端·javascript·后端
考虑考虑17 小时前
Excel导入时产生特殊字符处理
java·后端·java ee
IT_陈寒17 小时前
Redis的DEL命令竟然没删掉数据?我踩的这个坑你得知道
前端·人工智能·后端
用户9385156350717 小时前
Docker + Nginx + Node.js:从“我的电脑能跑,你的电脑跑不了”到一键部署
后端·nginx·docker
陆枫Larry17 小时前
两步验证(2FA )到底是什么?
后端
JavaGuide17 小时前
我用 Claude Code/ZCode+GLM-5.3 从零做了一款 Agent 游戏!
前端·后端