netty之编解码

简介:   1、netty的编码和解码,在数据传输的时候,考虑数据安全,数据完整性都是很有必要的。这里主要是介绍netty3和netty5的编解码方式。其实从StringEncoder和StringDecoder中也可以获取源码的编解码规则。

  1、netty的编码和解码,在数据传输的时候,考虑数据安全,数据完整性都是很有必要的。这里主要是介绍netty3和netty5的编解码方式。其实从StringEncoder和StringDecoder中也可以获取源码的编解码规则。然后改变成自己的编解码规则也是可以的。

  2、netty3和netty5的编解码方式还是存在一定差别的。个人感觉netty5来的更加实用和方便。

  3、netty3的编解码规则

  1)数据编码规则(我这里只是用于显示,数据规则很简单)

  包头+模块+数据(请求编解码)

  包头+模块+状态+数据(响应编解码)

  2)目录

  

  3)请求和相应对象

package com.troy.data.domain;

//请求数据
public class Request {

    //模块类型
    private int model;
    //数据
    private byte[] data;

    public int getModel() {
        return model;
    }

    public void setModel(int model) {
        this.model = model;
    }

    public byte[] getData() {
        return data;
    }

    public void setData(byte[] data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "Request{" +
                "model=" + model +
                ", data=" + new String(data) +
                '}';
    }
}
package com.troy.data.domain;

import java.util.Arrays;

//响应数据
public class Response {

    //模块类型
    private int model;
    //状态码
    private int status;
    //数据
    private byte[] data;


    public int getModel() {
        return model;
    }

    public void setModel(int model) {
        this.model = model;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public byte[] getData() {
        return data;
    }

    public void setData(byte[] data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "Response{" +
                "model=" + model +
                ", status=" + status +
                ", data=" + new String(data) +
                '}';
    }
}

  4)常量(这里的包头,因为是固定的就写了一个常量)

package com.troy.data.constant;

//常量
public class ConsantUtil {

    //固定常量用于数据拼接,确认
    public static final int PACKAGE_HEADER = -32523523;

}

  5)请求编解码

package com.troy.data.codec;

import com.troy.data.constant.ConsantUtil;
import com.troy.data.domain.Request;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;

public class RequestEncode extends OneToOneEncoder {

    protected Object encode(ChannelHandlerContext channelHandlerContext, Channel channel, Object o) throws Exception {

        Request request = (Request) o;
        ChannelBuffer channelBuffer = ChannelBuffers.dynamicBuffer();
        channelBuffer.writeInt(ConsantUtil.PACKAGE_HEADER);
        channelBuffer.writeInt(ConsantUtil.PACKAGE_HEADER);
        channelBuffer.writeBytes(request.getData());
        return channelBuffer;
    }
}
package com.troy.data.codec;

import com.troy.data.constant.ConsantUtil;
import com.troy.data.domain.Request;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.oneone.OneToOneDecoder;

//请求数据解码
public class RequestDecode extends OneToOneDecoder {

    protected Object decode(ChannelHandlerContext channelHandlerContext, Channel channel, Object o) throws Exception {
        ChannelBuffer channelBuffer = (ChannelBuffer) o;
        if (ConsantUtil.PACKAGE_HEADER == channelBuffer.readInt()) {
            Request request = new Request();
            request.setModel(channelBuffer.readInt());
            byte[] bytes = new byte[channelBuffer.readableBytes()];
            channelBuffer.readBytes(bytes);
            request.setData(bytes);
            return request;
        }
        return null;
    }
}

  6)响应编解码

package com.troy.data.codec;

import com.troy.data.constant.ConsantUtil;
import com.troy.data.domain.Response;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;

//响应编码器
public class ResponseEncode extends OneToOneEncoder {

    protected Object encode(ChannelHandlerContext channelHandlerContext, Channel channel, Object o) throws Exception {
        Response response = (Response) o;
        ChannelBuffer channelBuffer = ChannelBuffers.dynamicBuffer();
        channelBuffer.writeInt(ConsantUtil.PACKAGE_HEADER);
        channelBuffer.writeInt(response.getModel());
        channelBuffer.writeInt(response.getStatus());
        channelBuffer.writeBytes(response.getData());
        return channelBuffer;
    }
}
package com.troy.data.codec;

import com.troy.data.constant.ConsantUtil;
import com.troy.data.domain.Response;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.oneone.OneToOneDecoder;

//响应解码
public class ResponseDecode extends OneToOneDecoder{

    protected Object decode(ChannelHandlerContext channelHandlerContext, Channel channel, Object o) throws Exception {
            ChannelBuffer channelBuffer = (ChannelBuffer) o;
        if (ConsantUtil.PACKAGE_HEADER == channelBuffer.readInt()) {
            Response response = new Response();
            response.setModel(channelBuffer.readInt());
            response.setStatus(channelBuffer.readInt());
            byte[] bytes = new byte[channelBuffer.readableBytes()];
            channelBuffer.readBytes(bytes);
            response.setData(bytes);
            return response;
        }
        return null;
    }
}

  7)设置对应的管道编解码就可以了

  a、客户端

     //设置管道工厂
        clientBootstrap.setPipelineFactory(new ChannelPipelineFactory() {

            public ChannelPipeline getPipeline() throws Exception {
                ChannelPipeline channelPipeline = Channels.pipeline();
                channelPipeline.addLast("decode",new RequestEncode());
                channelPipeline.addLast("encode",new ResponseDecode());
                channelPipeline.addLast("client",new ClientHandler());
                return channelPipeline;
            }
        });
  @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
        Response response = (Response) e.getMessage();
        System.out.println(response.toString());
        super.messageReceived(ctx, e);
    }

  b、服务端

        //设置管道流
        serverBootstrap.setPipelineFactory(new ChannelPipelineFactory() {

            public ChannelPipeline getPipeline() throws Exception {
                ChannelPipeline channelPipeline = Channels.pipeline();
                //添加处理方式
                channelPipeline.addLast("idle",new IdleStateHandler(new HashedWheelTimer(),60,60,60));
                channelPipeline.addLast("decode",new RequestDecode());
                channelPipeline.addLast("encode",new ResponseEncode());
                channelPipeline.addLast("server",new ServerHandler());
                return channelPipeline;
            }
        });        
  @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
        Request request = (Request) e.getMessage();
        System.out.println("client:"+request.toString());
        Response response = new Response();
        response.setModel(1);
        response.setStatus(1);
        response.setData("hello client".getBytes());
        ctx.getChannel().write(response);
        super.messageReceived(ctx, e);
    }

  4、netty5的编解码规则

  1)数据结构、目录结构、对象、常量都是一样。

  2)编解码的编写方式有些不一样

  a、请求编解码

package com.troy.data.codec;

import com.troy.data.constant.ConsantUtil;
import com.troy.data.domain.Request;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;

import java.util.List;
@ChannelHandler.Sharable
public class RequestEncode extends MessageToMessageEncoder<Request> {

    protected void encode(ChannelHandlerContext channelHandlerContext, Request request, List<Object> list) throws Exception {
        ByteBuf byteBuf = Unpooled.buffer();
        byteBuf.writeInt(ConsantUtil.PACKAGE_HEADER);
        byteBuf.writeInt(request.getModel());
        byteBuf.writeBytes(request.getData());
        list.add(byteBuf);
    }
}
 
 
package com.troy.data.codec;

import com.troy.data.constant.ConsantUtil;
import com.troy.data.domain.Request;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;

import java.util.List;

//请求数据解码
@ChannelHandler.Sharable
public class RequestDecode extends MessageToMessageDecoder<ByteBuf>{

    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        if (ConsantUtil.PACKAGE_HEADER == byteBuf.readInt()) {
            //当数据超过指定值的时候跳过这部分数据
            if (byteBuf.readableBytes() > 2048) {
                byteBuf.skipBytes(byteBuf.readableBytes());
            }
            //一个字节一个字节的读取,知道读取到包头
            while(true) {
                byteBuf.markReaderIndex();
                if (ConsantUtil.PACKAGE_HEADER == byteBuf.readInt()) {
                    break;
                }
                byteBuf.resetReaderIndex();
                byteBuf.readByte();
            }
            Request request = new Request();
            request.setModel(byteBuf.readInt());
            byte[] bytes = new byte[byteBuf.readableBytes()];
            byteBuf.readBytes(bytes);
            request.setData(bytes);
            list.add(request);
        }
    }
}

  b、响应编解码

package com.troy.data.codec;

import com.troy.data.constant.ConsantUtil;
import com.troy.data.domain.Response;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;

import java.util.List;

//响应编码器
@ChannelHandler.Sharable
public class ResponseEncode extends MessageToMessageEncoder<Response> {

    protected void encode(ChannelHandlerContext channelHandlerContext, Response response, List<Object> list) throws Exception {
        ByteBuf byteBuf = Unpooled.buffer();
        byteBuf.writeInt(ConsantUtil.PACKAGE_HEADER);
        byteBuf.writeInt(response.getModel());
        byteBuf.writeInt(response.getStatus());
        byteBuf.writeBytes(response.getData());
        list.add(byteBuf);
    }
}
 
 
package com.troy.data.codec;

import com.troy.data.constant.ConsantUtil;
import com.troy.data.domain.Response;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;

import java.util.List;

//响应解码
@ChannelHandler.Sharable
public class ResponseDecode extends MessageToMessageDecoder<ByteBuf>{

    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        if (ConsantUtil.PACKAGE_HEADER == byteBuf.readInt()) {
            //当数据超过指定值的时候跳过这部分数据
            if (byteBuf.readableBytes() > 2048) {
                byteBuf.skipBytes(byteBuf.readableBytes());
            }
            //一个字节一个字节的读取,知道读取到包头
            while(true) {
                byteBuf.markReaderIndex();
                if (ConsantUtil.PACKAGE_HEADER == byteBuf.readInt()) {
                    break;
                }
                byteBuf.resetReaderIndex();
                byteBuf.readByte();
            }
            Response response = new Response();
            response.setModel(byteBuf.readInt());
            response.setStatus(byteBuf.readInt());
            byte[] bytes = new byte[byteBuf.readableBytes()];
            byteBuf.readBytes(bytes);
            response.setData(bytes);
            list.add(response);
        }
    }
}

  3)处理上面基本上都是一样的。

  5、netty的编解码,主要目的就是处理通讯问题,对数据进行自定义处理!

   6、源码下载:https://pan.baidu.com/s/1nvUnmEt

相关文章
|
6月前
|
编解码
Netty Review - 优化Netty通信:如何应对粘包和拆包挑战_自定义长度分包编解码码器
Netty Review - 优化Netty通信:如何应对粘包和拆包挑战_自定义长度分包编解码码器
92 0
|
6月前
|
编解码 JSON 网络协议
Netty使用篇:Http协议编解码
Netty使用篇:Http协议编解码
|
编解码 网络协议 Java
搞懂Netty(3)使用MessagePack解决编解码问题
使用Netty主要是为了进行网络通信,而网络通信就要涉及到传输数据,数据是不能直接传递的,需要进行一系列处理。java序列化就是其中一种处理方式,但是由于各种各样的缺点,一般不会用,在这里我们介绍一个比较优秀的编码解码技术MessagePack。 这篇文章是我的《搞懂Netty》系列的第三篇,也是在前两篇文章的基础之上进行讲解的。我们使用的是Springboot整合的Netty。
228 0
搞懂Netty(3)使用MessagePack解决编解码问题
|
存储 设计模式 缓存
图文并茂剖析Netty编解码以及背后的设计理念
图文并茂剖析Netty编解码以及背后的设计理念
图文并茂剖析Netty编解码以及背后的设计理念
|
消息中间件 编解码 移动开发
Netty常用招式——ChannelHandler与编解码(二)
Netty常用招式——ChannelHandler与编解码(二)
176 0
Netty常用招式——ChannelHandler与编解码(二)
|
存储 编解码 网络协议
Netty常用招式——ChannelHandler与编解码(一)
Netty常用招式——ChannelHandler与编解码(一)
218 0
Netty常用招式——ChannelHandler与编解码(一)
|
XML 存储 编解码
如何修正Netty编解码的缺陷
如何修正Netty编解码的缺陷
125 0
如何修正Netty编解码的缺陷
|
存储 缓存 NoSQL
跟着源码学IM(十一):一套基于Netty的分布式高可用IM详细设计与实现(有源码)
本文将要分享的是如何从零实现一套基于Netty框架的分布式高可用IM系统,它将支持长连接网关管理、单聊、群聊、聊天记录查询、离线消息存储、消息推送、心跳、分布式唯一ID、红包、消息同步等功能,并且还支持集群部署。
13485 1
|
6月前
|
消息中间件 Oracle Dubbo
Netty 源码共读(一)如何阅读JDK下sun包的源码
Netty 源码共读(一)如何阅读JDK下sun包的源码
126 1
|
11月前
|
NoSQL Java Redis
跟着源码学IM(十二):基于Netty打造一款高性能的IM即时通讯程序
关于Netty网络框架的内容,前面已经讲了两个章节,但总归来说难以真正掌握,毕竟只是对其中一个个组件进行讲解,很难让诸位将其串起来形成一条线,所以本章中则会结合实战案例,对Netty进行更深层次的学习与掌握,实战案例也并不难,一个非常朴素的IM聊天程序。 原本打算做个多人斗地主练习程序,但那需要织入过多的业务逻辑,因此一方面会带来不必要的理解难度,让案例更为复杂化,另一方面代码量也会偏多,所以最终依旧选择实现基本的IM聊天程序,既简单,又能加深对Netty的理解。
157 1