之前写的nettydemmo都是传递字符串的,而在真实使用的时候我们传的都是对象,然后写序列化方法进行序列化和返序列化,在netty中对序列化和返序列化都提供了相应的接口,而且netty也支持很多的序列化方式,但这里先提供java的序列化实现方式。
一、java序列化方式
package com.decode;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
/**
* Java序列化工具
*
* @author whd
* @date 2017年11月6日 上午9:24:35
*/
public class Utils {
public byte[] encodes(Object obj) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(obj);
oos.flush();
oos.close();
byte[] bytes = out.toByteArray();
return bytes;
}
public Object decode(byte[] bytes) throws IOException, ClassNotFoundException {
// 对象返序列化
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
ObjectInputStream inn = new ObjectInputStream(in);
Object obj = inn.readObject();
return obj;
}
/**
* byte to buf
*
* @param bytes
* @return
*/
public ByteBuf getBufFromByte(byte[] bytes) {
ByteBuf buf = Unpooled.copiedBuffer(bytes);
return buf;
}
/**
* buf to byte
*
* @param buf
* @return
*/
public byte[] getByteFromBuf(ByteBuf buf) {
int size = buf.readableBytes();
byte[] bytes = new byte[size];
buf.readBytes(bytes);
return bytes;
}
}
二、Netty中提供的序列化,返序列化接口
1、Encoder(编码)
package com.rpc;
import com.decode.Utils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
/**
* netty中的编码
*
* @author whd
* @date 2017年12月3日 下午7:43:23
*/
public class Encoder extends MessageToByteEncoder<Object> {
/**
* 我们知道在计算机中消息的交互都是byte 但是在netty中进行了封装所以在netty中基本的传递类型是ByteBuf
*/
@Override
protected void encode(ChannelHandlerContext ctx, Object in, ByteBuf out) throws Exception {
Utils util = new Utils();
byte[] bytes = util.encodes(in);
out.writeBytes(bytes);
}
}
2、Decoder(解码)
package com.rpc;
import java.util.List;
import com.decode.Utils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
/**
* 解码
*
* @author whd
* @date 2017年11月6日 下午1:56:45
*/
public class Decoder extends ByteToMessageDecoder {
private static final int LENGTH = 4;
/**
* 解码时传进来的参数是ByteBuf也就是Netty的基本单位,而传出的是解码后的Object
*/
@Override
protected void decode(ChannelHandlerContext arg0, ByteBuf in, List<Object> out) throws Exception {
Utils util = new Utils();
int size = in.readableBytes();
// 这里判断大小是为了tcp的粘包问题,这个之后再单独学习
if (size > Decoder.LENGTH) {
byte[] bytes = util.getByteFromBuf(in);
Object info = util.decode(bytes);
out.add(info);
}
}
}
注意netty的4.+版本和5.0版本区别还是有点大所以在使用的时候要注意一下,这里使用的是netty的5.0版本!!!
OK这样编码解码OK了,在netty中使用编码解码很简单,之前说过了netty对channel中的消息的处理是链式也就是channelPipeline ,所以在我们实现了编解码之后使用时直接添加到channelpipeline中就OK了:
客户端channelpipeline:
private class InitializerChannel extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new Encoder());
pipeline.addLast(new Decoder());
pipeline.addLast(new ClientHandler());
}
}服务端channelpipeline:
private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline cp = ch.pipeline();
cp.addLast(new Decoder());
cp.addLast(new Encoder());
cp.addLast(new ServerHandler());
}
}编码解码流程:
client Application 将Object写出到netty的channel,然后channelPipeline 链式按照配置的将Object转化为byte 写到tcp缓存,然后网络传出
服务端从服务端Tcp缓存读取客户端传递过来的byte流,这时就会从tcp缓存进入serverApplication 这时在进入netty的channelPipeline 首先要做的就是将byte解码为Object,使用的就是我们在pipeline中配置的解码器,这样我们在channelRead()方法中获取的就是解码后的Object了,可以直接转化为我们需要的对象来处理,这样就很方便!
从服务端响应消息到客户端也是一样的流程!
本文介绍如何在Netty中使用Java序列化实现对象的编码与解码,包括自定义序列化工具类及实现Netty提供的Encoder与Decoder接口,并展示了如何在客户端和服务端ChannelPipeline中配置这些组件。
803

被折叠的 条评论
为什么被折叠?



