专栏首页CodeGuide | 程序员编码指南netty案例,netty4.1基础入门篇九《自定义编码解码器》

netty案例,netty4.1基础入门篇九《自定义编码解码器》

前言介绍

在实际应用场景里,只要是支持sokcet通信的都可以和Netty交互,比如中继器、下位机、PLC等。这些场景下就非常需要自定义编码解码器,来处理字节码传输,并控制半包、粘包以及安全问题。那么本章节我们通过实现ByteToMessageDecoder、MessageToByteEncoder来实现我们的需求。

环境准备

1、jdk1.8【jdk1.7以下只能部分支持netty】 2、Netty4.1.36.Final【netty3.x 4.x 5每次的变化较大,接口类名也随着变化】 3、telnet 测试【可以现在你的win7机器上测试这个命令,用于链接到服务端的测试命令】

代码示例

itstack-demo-netty-1-09
└── src
    ├── main
    │   └── java
    │       └── org.itstack.demo.netty
    │           ├── codec
    │           │   ├── MyDecoder.java
    │           │   └── MyEncoder.java
    │           └── server
    │               ├── MyChannelInitializer.java
    │               ├── MyServerHandler.java
    │               └── NettyServer.java
    └── test
         └── java
             └── org.itstack.demo.test
                 └── ApiTest.java

MyDecoder.java *用于处理解码,02开始 03结束

public class MyDecoder extends ByteToMessageDecoder {

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf in, List<Object> out) throws Exception {
        int size = in.readableBytes();

        byte[] data = new byte[size];
        in.readBytes(data);

        byte begin = data[0];     //开始符02
        byte end = data[size - 1];//结束符03

        //无开始符,只有结束符,数据丢包
        if (begin != 0x02 && end == 0x03){
            System.out.println("公众号:bugstack虫洞栈 提示;byteBuf数据,无开始符,只有结束符,数据丢包。");
            channelHandlerContext.writeAndFlush("error");
            return; //直接返回,不置位指针
        }
        //有开始符,无结束符号,数据半包。置位指针,接收余下数据
        if (begin != 0x02 || end != 0x03) {
            in.resetReaderIndex();
            System.out.println("公众号:bugstack虫洞栈 提示;byteBuf数据,有开始符,无结束符号,数据半包。置位指针,接收余下数据。");
            return;
        }
        //数据完整,解析处理
        System.out.println(JSON.toJSONString(data));
        //越过02 03位
        ByteBuf copy = in.copy(1, size - 1);
        //转换
        String msg = copy.toString(Charset.forName("GBK"));
        //填充
        out.add(msg);
    }

}

MyEncoder.java *用于处理编码,在byte开始和结束加上02 03

public class MyEncoder extends MessageToByteEncoder {

    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, Object in, ByteBuf out) throws Exception {

        String msg = in.toString();
        byte[] bytes = msg.getBytes();

        byte[] send = new byte[bytes.length + 2];
        System.arraycopy(bytes, 0, send, 1, bytes.length);
        send[0] = 0x02;
        send[send.length - 1] = 0x03;

        out.writeInt(send.length);
        out.writeBytes(send);

    }

}

MyChannelInitializer.java

public class MyChannelInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel channel) {
        //自定义解码器
        channel.pipeline().addLast(new MyDecoder());
        //自定义编码器
        channel.pipeline().addLast(new MyEncoder());
        //在管道中添加我们自己的接收数据实现方法
        channel.pipeline().addLast(new MyServerHandler());
    }

}

MyServerHandler.java

public class MyServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        SocketChannel channel = (SocketChannel) ctx.channel();
        System.out.println("链接报告开始 {公众号:bugstack虫洞栈 >获取学习源码}");
        System.out.println("链接报告信息:有一客户端链接到本服务端");
        System.out.println("链接报告IP:" + channel.localAddress().getHostString());
        System.out.println("链接报告Port:" + channel.localAddress().getPort());
        System.out.println("链接报告完毕");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        //接收msg消息{与上一章节相比,此处已经不需要自己进行解码}
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " 接收到消息:" + msg);

        ctx.writeAndFlush("hi I'm ok");
    }

}

测试结果

启动NettyServer

itstack-demo-netty server start done. {关注公众号:bugstack虫洞栈,获取源码}
链接报告开始 {公众号:bugstack虫洞栈 >获取学习源码}
链接报告信息:有一客户端链接到本服务端
链接报告IP:192.168.1.121
链接报告Port:7397
链接报告完毕
"AmhpILmr1tq6xaO6YnVnc3RhY2uz5ra01bsgAw=="
2019-08-18 15:32:47 接收到消息:hi 公众号:bugstack虫洞栈 
"AmhpILmr1tq6xaO6YnVnc3RhY2uz5ra01bsgAw=="
2019-08-18 15:32:48 接收到消息:hi 公众号:bugstack虫洞栈 
"AmhpILmr1tq6xaO6YnVnc3RhY2uz5ra01bsgAw=="
2019-08-18 15:32:49 接收到消息:hi 公众号:bugstack虫洞栈 
"AmhpILmr1tq6xaO6YnVnc3RhY2uz5ra01bsgAw=="
2019-08-18 15:32:49 接收到消息:hi 公众号:bugstack虫洞栈 
"AmhpILmr1tq6xaO6YnVnc3RhY2uz5ra01bsgAw=="
2019-08-18 15:32:50 接收到消息:hi 公众号:bugstack虫洞栈 
"AmhpILmr1tq6xaO6YnVnc3RhY2uz5ra01bsgAw=="
2019-08-18 15:32:51 接收到消息:hi 公众号:bugstack虫洞栈 
"AmhpILmr1tq6xaO6YnVnc3RhY2uz5ra01bsgAw=="
2019-08-18 15:32:51 接收到消息:hi 公众号:bugstack虫洞栈 

Process finished with exit code -1

启动模拟器NetAssist,用TcpClient链接服务端

本文分享自微信公众号 - bugstack虫洞栈(bugstack),作者:付政委

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • netty案例,netty4.1中级拓展篇二《Netty使用Protobuf传输数据》

    在netty数据传输过程中可以有很多选择,比如;字符串、json、xml、java对象,但为了保证传输的数据具备;良好的通用性、方便的操作性和传输的高性能,我们...

    小傅哥
  • netty案例,netty4.1基础入门篇九《自定义编码解码器,处理半包、粘包数据》

    在实际应用场景里,只要是支持sokcet通信的都可以和Netty交互,比如中继器、下位机、PLC等。这些场景下就非常需要自定义编码解码器,来处理字节码传输,并控...

    小傅哥
  • netty案例,netty4.1基础入门篇七《嗨!NettyClient》

    在前六章的案例中使用socket模拟器链接我们的NettyServer,进行通信测试。本章节我们写一个helloworld版的NettyClient客户端,与我...

    小傅哥
  • Redis 和 MySQL 数据保持一致

    数据首先都写到数据库,之后更新redis(先写redis再写mysql,如果写入失败事务回滚会造成redis中存在脏数据)

    php007
  • Apriori算法实例——322万知乎用户的关注话题关联分析

    ? 用以前爬的知乎用户行为数据,跑了一下Apriori算法,发现了一些有意思的关联规则。以下是简略的分析过程。数据采集数据怎么来的?当然不是知乎给的,是爬虫来...

    小莹莹
  • 理解Java Integer的缓存策略

    本文将介绍 Java 中 Integer 缓存的相关知识。这是 Java 5 中引入的一个有助于节省内存、提高性能的特性。首先看一个使用 Integer 的示例...

    哲洛不闹
  • 估值一个亿的AI核心代

    良月柒
  • 【大型网站技术架构笔记】(二)大型网站架构模式与核心要素

    即对系统进行横向划分。比如进行MVC分层,又可分为接入层、业务层、核心数据层。应当禁止跨层调用以及逆向调用。

    吃橙子的狐狸
  • 简述 HTTP 首部字段.

    HTTP 首部字段是构成 HTTP 报文的要素之一。在客户端与服务器之间以 HTTP 协议进行通信的过程中,无论是请求还是响应都会使用首部字段,它能起到传递额外...

    JMCui
  • 世界接吻日|吻你千千万万遍,Love is now or never

    每年的7月6日都是世界接吻日(也叫国际接吻日),这由英国人率先发起,1991年得到联合国承认。在今天,你可以亲吻所有你喜欢的人(当然了,对方得同意)~

    VRPinea

扫码关注云+社区

领取腾讯云代金券