Netty中对象的序列化,反序列化

本文介绍如何在Netty中使用Java序列化实现对象的编码与解码,包括自定义序列化工具类及实现Netty提供的Encoder与Decoder接口,并展示了如何在客户端和服务端ChannelPipeline中配置这些组件。

之前写的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了,可以直接转化为我们需要的对象来处理,这样就很方便!

从服务端响应消息到客户端也是一样的流程!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值