Netty--JDK序列化编解码传输对象
使用JDK序列化不需要额外的类库,只需要实现Serializable即可,但是序列化之后的码流只有Java才能反序列化,所以它不是跨语言的,另外由于Java序列化后码流比较大,效率也不高,所以在RPC中很少使用,本文只是做学习之用。
编解码器:
public class JdkDecoder extends MessageToMessageDecoder<ByteBuf> {
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
final int length = byteBuf.readableBytes();
final byte[] b = new byte[length];
byteBuf.getBytes(byteBuf.readerIndex(), b, 0, length);
ByteArrayInputStream bis = new ByteArrayInputStream(b);
ObjectInputStream ois = new ObjectInputStream(bis);
list.add(ois.readObject());
ois.close();
}
}
public class JdkEncoder extends MessageToByteEncoder<Object> {
@Override
protected void encode(ChannelHandlerContext channelHandlerContext, Object o, ByteBuf byteBuf) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(o);
oos.flush();
byteBuf.writeBytes(bos.toByteArray());
bos.close();
oos.close();
}
}
---
传输对象:
public class Person implements Serializable{
private int age;
private String name;
private boolean man;
private List<String> list;
private Date birth;
private Person son;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
。。。
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
", man=" + man +
", list=" + list +
", birth=" + birth +
", son=" + son +
'}';
}
}
---
Server端:
public class EchoServer {
public static void main(String[] args) {
new EchoServer().bind(8080);
}
public void bind(int port) {
//配置服务端的线程组,一个用于服务端接收客户端连接,另一个进行SocketChannel的网络读写
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//ServerBootstrap用于启动NIO服务端的辅助启动类
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
//.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
//
ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(65535, 0, 2, 0, 2));
//ch.pipeline().addLast(new MsgpackDecoder());
ch.pipeline().addLast(new JdkDecoder());
//在报文前增加2个字节,写消息长度
ch.pipeline().addLast(new LengthFieldPrepender(2));
//ch.pipeline().addLast(new MsgpackEncoder());
ch.pipeline().addLast(new JdkEncoder());
ch.pipeline().addLast(new EchoServerHandler());
}
});
//绑定端口,sync为同步阻塞方法,等待绑定成功,ChannelFuture用于异步操作的通知回调
ChannelFuture future = bootstrap.bind(port).sync();
System.out.println("server started");
//等待服务端监听端口关闭
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("server shuting down");
//释放线程资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
int count = 0;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if(msg instanceof Person){
Person p = (Person)msg;
Q.p(p.toString());
}else {
System.out.println("The server received(" + count++ + "): " + msg);
}
ctx.writeAndFlush(msg);//异步发送
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
---
Client端:
public class EchoClient {
public static void main(String[] args) {
new EchoClient().connect("127.0.0.1", 8080);
}
public void connect(String host, int port) {
//配置客户端NIO线程组
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(65535, 0, 2, 0, 2));
//ch.pipeline().addLast(new MsgpackDecoder());
ch.pipeline().addLast(new JdkDecoder());
ch.pipeline().addLast(new LengthFieldPrepender(2));
//ch.pipeline().addLast(new MsgpackEncoder());
ch.pipeline().addLast(new JdkEncoder());
ch.pipeline().addLast(new EchoClientHandler());
}
});
//发起异步连接操作,同步等待连接成功
ChannelFuture future = bootstrap.connect(host, port).sync();
System.out.println("client started");
//等待客户端链路关闭
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("client shuting down");
//释放NIO线程组
group.shutdownGracefully();
}
}
}
public class EchoClientHandler extends ChannelInboundHandlerAdapter {
private int count = 0;
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
List l = new ArrayList<String>();
l.add("abc");
l.add("123");
Person p = new Person();
p.setName("luangeng");
p.setMan(true);
p.setBirth(new Date());
p.setList(l);
for (int i = 0; i < 10; i++) {
p.setAge(i);
ctx.write(p);
}
ctx.flush();
}
//服务端返回应答信息后调用
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if(msg instanceof Person){
Person p = (Person)msg;
Q.p(p.toString());
}else {
Q.p(count++ + " client get: " + msg);
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
---
执行结果:
client started
Person{age=0, name='luangeng', man=true, list=[abc, 123], birth=Wed Nov 22 21:18:48 CST 2017, son=null}
Person{age=1, name='luangeng', man=true, list=[abc, 123], birth=Wed Nov 22 21:18:48 CST 2017, son=null}
Person{age=2, name='luangeng', man=true, list=[abc, 123], birth=Wed Nov 22 21:18:48 CST 2017, son=null}
Person{age=3, name='luangeng', man=true, list=[abc, 123], birth=Wed Nov 22 21:18:48 CST 2017, son=null}
Person{age=4, name='luangeng', man=true, list=[abc, 123], birth=Wed Nov 22 21:18:48 CST 2017, son=null}
Person{age=5, name='luangeng', man=true, list=[abc, 123], birth=Wed Nov 22 21:18:48 CST 2017, son=null}
Person{age=6, name='luangeng', man=true, list=[abc, 123], birth=Wed Nov 22 21:18:48 CST 2017, son=null}
Person{age=7, name='luangeng', man=true, list=[abc, 123], birth=Wed Nov 22 21:18:48 CST 2017, son=null}
Person{age=8, name='luangeng', man=true, list=[abc, 123], birth=Wed Nov 22 21:18:48 CST 2017, son=null}
Person{age=9, name='luangeng', man=true, list=[abc, 123], birth=Wed Nov 22 21:18:48 CST 2017, son=null}
Netty也提供了基于JDK的编解码器,可以直接使用,比如:
channel.pipeline()
.addLast(new LengthFieldBasedFrameDecoder(65535, 0, 4, 0, 4))
.addLast(new ObjectDecoder(ClassResolvers.weakCachingConcurrentResolver(this.getClass().getClassLoader())))
.addLast(new LengthFieldPrepender(4))
.addLast(new ObjectEncoder())
.addLast(new ServerHandler());
---
MessagePack工具:
MessagePack是与JSON数据格式类似的二进制序列化格式,更快更小,并且是跨语言的,用于在多个语言之间交换数据。使用MessagePack实现的编解码器如下:
public class MsgpackEncoder extends MessageToByteEncoder<Object> {
@Override
protected void encode(ChannelHandlerContext channelHandlerContext, Object o, ByteBuf byteBuf) throws Exception {
MessagePack mp = new MessagePack();
byte[] raw = mp.write(o);
byteBuf.writeBytes(raw);
}
}
public class MsgpackDecoder extends MessageToMessageDecoder<ByteBuf> {
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
final int length = byteBuf.readableBytes();
final byte[] b = new byte[length];
byteBuf.getBytes(byteBuf.readerIndex(), b, 0, length);
MessagePack mp = new MessagePack();
list.add(mp.read(b));
}
}
---
使用这种编解码后,服务端和客户端接收到的对象都不能转换为Person对象。
end
Netty--JDK序列化编解码传输对象的更多相关文章
- Netty对常用编解码的支持
参考文献:极客时间傅健老师的<Netty源码剖析与实战>Talk is cheap.show me the code! Netty对编解码的支持 打开Netty的源码,它对很多的编码器都提 ...
- JDK Base64编解码1.7和1.8的坑
场景 对接一个第三方api接口,其中签名部分用的是JDK8的编码.我们线上采用JDK7,导致项目无法编译 替换编解码部分为1.7的代码,然后签名又不对 所以坑就在这里,结论,1.7的编解码有换行符导致 ...
- 【转】Netty系列之Netty编解码框架分析
http://www.infoq.com/cn/articles/netty-codec-framework-analyse/ 1. 背景 1.1. 编解码技术 通常我们也习惯将编码(Encode)称 ...
- Netty系列之Netty编解码框架分析
1. 背景 1.1. 编解码技术 通常我们也习惯将编码(Encode)称为序列化(serialization),它将对象序列化为字节数组,用于网络传输.数据持久化或者其它用途. 反之,解码(Decod ...
- (中级篇 NettyNIO编解码开发)第七章-java序列化
相信大多数Java程序员接触到的第一种序列化或者编解码技术就是.Java的默认序列化,只需要序列化的POJO对象实现java.io.Serializable接口,根据实际情况生成序列ID,这个类就能够 ...
- 从零开始实现简单 RPC 框架 7:网络通信之自定义协议(粘包拆包、编解码)
当 RPC 框架使用 Netty 通信时,实际上是将数据转化成 ByteBuf 的方式进行传输. 那如何转化呢?可不可以把 请求参数 或者 响应结果 直接无脑序列化成 byte 数组发出去? 答:直接 ...
- (中级篇 NettyNIO编解码开发)第八章-Google Protobuf 编解码-2
8.1.2 Protobuf编解码开发 Protobuf的类库使用比较简单,下面我们就通过对SubscrjbeReqProto进行编解码来介绍Protobuf的使用. 8-1 Protob ...
- JAVA基础4---序列化和反序列化深入整理(JDK序列化)
一.什么是序列化和反序列化? 序列化:将对象状态信息转化成可以存储或传输的形式的过程(Java中就是将对象转化成字节序列的过程) 反序列化:从存储文件中恢复对象的过程(Java中就是通过字节序列转化成 ...
- netty: 编解码之jboss marshalling, 用marshalling进行对象传输
jboss marshalling是jboss内部的一个序列化框架,速度也十分快,这里netty也提供了支持,使用十分方便. TCP在网络通讯的时候,通常在解决TCP粘包.拆包问题的时候,一般会用以下 ...
随机推荐
- ZOJ 2283 Challenge of Wisdom 数论,Dilworth Theorem,求最长反链 难度:2
Challenge of Wisdom Time Limit: 2 Seconds Memory Limit: 32768 KB Background "Then, I want ...
- C#常用函数与方法集合
1.DateTime 数字型 System.DateTime currentTime=new System.DateTime(); 1.1 取当前年月日时分秒 ...
- 通过fork进程爆破canary
1.1.1 通过fork进程爆破canary ⑴.原理分析: 对fork而言,作用相当于自我复制,每一次复制出来的程序,内存布局都是一样的,当然canary值也一样.那我们就可以逐位爆破,如果程 ...
- LeetCode OJ:Climbing Stairs(攀爬台阶)
You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb ...
- UE4 引擎基础类说明
本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/76048437 作者:car ...
- js `` 手机不支持
- matlab save 命令
有时候要运行很长才得到结果,而这部分结果在后面修改代码之后不需要改变.可以多次利用这些结果or参数,有必要将结果保存下来. 1 save example1 A ;%A为当前环境下的变量,example ...
- jquery.i18n.properties.js hacking
/****************************************************************************** * jquery.i18n.proper ...
- excel中多表汇总
excel中将多个表中的结果汇总到一张表格里,而且汇总表格的数据是随着其它表格的数据变化面变化 其实就是函数sumif的使用,sumif函数的结构: sumif函数语法 sumif(range,cri ...
- ubuntu安装lua5.3.2
lua5.3要自主编译安装 1.获取源:weget http://www.lua.org/ftp/lua-5.3.2.tar.gz 2.解压:tar -zxf lua-5.3.2.tar.gz 3.编 ...