周末 文章走起。前面文章介绍Netty相关知识点。接下来将介绍下在通信过程中用的编码器和解码器。这里会不会联想到谍战戏里面。发送情报者怕情报泄露,所以对情报行加密然后传给接收者。接收者对情报进行解密,得到情报。这里讲的编码器和解码器是和情报传递很相似?一起查看这篇文章,来揭秘!!!
一 编解码器
1.1 什么叫编解码器
在网络传输的过程中,数据都是以字节流的方式进行传递。客户端在向服务端发送数据的时候,将业务中其他类型数据转化为字节,叫编码。服务端接收到数据为字节流,将字节流转化为原来的格式,叫解码。统称codec。
编解码器分为两部分-编码器和解码器,编码器负责出站,解码器负责入站。
1.2 解码器
1.2.1 概述
解码器负责入站操作,那么也一定要实现ChannelInboundHandler接口,所以解码器本质 上也是ChannelHandler。我们自定义编解码器只需要继承ByteToMessageDecoder(Netty提供抽象类,继承 ChannelInboundHandlerAdapter),实现decode()。Netty提供一些常用的解码器实现, 开箱即用。如下:
1 RedisDecoder 基于Redis协议的解码器
2 XmlDecoder 基于XML格式的解码器
3 JsonObjectDecoder 基于json数据格式的解码器
4 HttpObjectDecoder 基于http协议的解码器
Netty也提供了MessageToMessageDecoder,将⼀种格式转化为另⼀种格式的解码器,也提供了⼀些 实现,如下:
1 StringDecoder 将接收到ByteBuf转化为字符串
2 ByteArrayDecoder 将接收到ByteBuf转化字节数组
3 Base64Decoder 将由ByteBuf或US-ASCII字符串编码的Base64解码为ByteBuf。
1.2.2 将字节流转化为Intger类型(案例)
1. 字节解码器
package com.haopt.netty.codec;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.util.List;
public class ByteToIntegerDecoder extends ByteToMessageDecoder {
/**
*
* @param ctx 上下⽂
* @param in 输⼊的ByteBuf消息数据
* @param out 转化后输出的容器
* @throws Exception
*/
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
if(in.readableBytes() >= 4){ //int类型占⽤4个字节,所以需要判断是否存在有4个字节,再进⾏读取
out.add(in.readInt()); //读取到int类型数据,放⼊到输出,完成数据类型的转化
}
}
}
2. Handler
package com.haopt.netty.codec;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class ServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Integer i = (Integer) msg; //这⾥可以直接拿到Integer类型的数据
System.out.println("服务端接收到的消息为:" + i);
}
}
3 在pipeline中添加解码器
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
.addLast(new ByteToIntegerDecoder())
.addLast(new ServerHandler());
}
可以将代码复制到IDEA运行下,查看下运行效果。
1.3 编码器
1.3.1 概述
将原来的格式转化为字节。我们要实现自定义解码器只要继承MessageToByteEncoder(实现了ChannelOutboundHandler接⼝),本质上也是ChannelHandler。Netty中一些实现的编码器,如下:
1 ObjectEncoder 将对象(需要实现Serializable接⼝)编码为字节流
2 SocksMessageEncoder 将SocksMessage编码为字节流
3 HAProxyMessageEncoder 将HAProxyMessage编码成字节流
Netty也提供了MessageToMessageEncoder,将⼀种格式转化为另⼀种格式的编码器,也提供了⼀些 实现:
1 RedisEncoder 将Redis协议的对象进⾏编码
2 StringEncoder 将字符串进⾏编码操作
3 Base64Encoder 将Base64字符串进⾏编码操作
1.3.2 将Integer类型编码为字节进⾏传递(案例)
1. 自定义编码器
package com.haopt.netty.codec.client;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
public class IntegerToByteEncoder extends MessageToByteEncoder<Integer> {
@Override
protected void encode(ChannelHandlerContext ctx, Integer msg, ByteBuf out) throws Exception {
out.writeInt(msg);
}
}
2. Handler
package com.haopt.netty.codec.client;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;
public class ClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
System.out.println("接收到服务端的消息:" +
msg.toString(CharsetUtil.UTF_8));
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(123);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
3. pipeline
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new IntegerToByteEncoder());
ch.pipeline().addLast(new ClientHandler());
}
二 开发Http服务器
通过Netty中提供的http的解码器,进行http服务器开发。建议代码复制下来,执行下看看效果。
2.1 Netty配置
1. server
package