使用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序列化编解码传输对象的更多相关文章

  1. Netty对常用编解码的支持

    参考文献:极客时间傅健老师的<Netty源码剖析与实战>Talk is cheap.show me the code! Netty对编解码的支持 打开Netty的源码,它对很多的编码器都提 ...

  2. JDK Base64编解码1.7和1.8的坑

    场景 对接一个第三方api接口,其中签名部分用的是JDK8的编码.我们线上采用JDK7,导致项目无法编译 替换编解码部分为1.7的代码,然后签名又不对 所以坑就在这里,结论,1.7的编解码有换行符导致 ...

  3. 【转】Netty系列之Netty编解码框架分析

    http://www.infoq.com/cn/articles/netty-codec-framework-analyse/ 1. 背景 1.1. 编解码技术 通常我们也习惯将编码(Encode)称 ...

  4. Netty系列之Netty编解码框架分析

    1. 背景 1.1. 编解码技术 通常我们也习惯将编码(Encode)称为序列化(serialization),它将对象序列化为字节数组,用于网络传输.数据持久化或者其它用途. 反之,解码(Decod ...

  5. (中级篇 NettyNIO编解码开发)第七章-java序列化

    相信大多数Java程序员接触到的第一种序列化或者编解码技术就是.Java的默认序列化,只需要序列化的POJO对象实现java.io.Serializable接口,根据实际情况生成序列ID,这个类就能够 ...

  6. 从零开始实现简单 RPC 框架 7:网络通信之自定义协议(粘包拆包、编解码)

    当 RPC 框架使用 Netty 通信时,实际上是将数据转化成 ByteBuf 的方式进行传输. 那如何转化呢?可不可以把 请求参数 或者 响应结果 直接无脑序列化成 byte 数组发出去? 答:直接 ...

  7. (中级篇 NettyNIO编解码开发)第八章-Google Protobuf 编解码-2

    8.1.2    Protobuf编解码开发 Protobuf的类库使用比较简单,下面我们就通过对SubscrjbeReqProto进行编解码来介绍Protobuf的使用. 8-1    Protob ...

  8. JAVA基础4---序列化和反序列化深入整理(JDK序列化)

    一.什么是序列化和反序列化? 序列化:将对象状态信息转化成可以存储或传输的形式的过程(Java中就是将对象转化成字节序列的过程) 反序列化:从存储文件中恢复对象的过程(Java中就是通过字节序列转化成 ...

  9. netty: 编解码之jboss marshalling, 用marshalling进行对象传输

    jboss marshalling是jboss内部的一个序列化框架,速度也十分快,这里netty也提供了支持,使用十分方便. TCP在网络通讯的时候,通常在解决TCP粘包.拆包问题的时候,一般会用以下 ...

随机推荐

  1. JDBC的步骤

    使用jdbc步骤 a.导入数据库厂商提供的驱动程序(导入jar包) b.加载驱动程序 Class.forName("驱动程序类") c.获得连接 Connection conn=D ...

  2. Spring AOP的使用报错!

    用构造方法注入的时候 需要把无参构造方法手动加上 AOP底层会调用无参构造方法. 不加则报错:Superclass has no null constructors but no arguments ...

  3. 实现DQN算法玩CartPole

    先安装tensorflow 1.2版本和python 3.6, 接着安装: numpy-1.13.1+mkl-cp36-cp36m-win_amd64.whl 的版本,这个是windows下的,如果l ...

  4. Linux 大文件的分割与合并

    1.分割 -- split命令 可以指定按行数分割和按字节大小分割两种模式. (1) 按行数分割 $ large_file.txt new_file_prefix 加上-d,使用数字后缀:加上--ve ...

  5. iOS中数组遍历的方法及比较

    数组遍历是编码中很常见的一种需求,我们来扒一拔iOS里面都有什么样的方法来实现,有什么特点. 因为ios是兼容C语言的,所以c语言里面的最最常见的for循环遍历是没有问题的. 本文中用的数组是获取的系 ...

  6. iOS-分组UITableView删除崩溃问题(当删除section中最后一条数据崩溃的情况)

    错误: The number of sections contained in the table view after the update (1) must be equal to the num ...

  7. 如何看待 Kotlin 成为 Android 官方支持开发语言?

    Google IO 2017宣布了 Kotlin 会成为 Android 官方开发语言.一时间朋友圈和Android圈被各种刷屏.当然我也顺势而为发布了一篇的文章<为什么我要改用Kotlin&g ...

  8. python类中self是什么

    参考文献:http://www.cnblogs.com/linuxcat/archive/2012/01/05/2220997.html 注: (1)self在定义类的方法时是必须有的. (2)调用时 ...

  9. django-xhtml2pdf的使用(加入图片,指定字体,设置样式)

    新博客地址:http://muker.net/django-xhtml2pdf.html 这里仅仅讨论直接利用html生成pdf这种最常见也最简单的情况. 1.要利用html生成带中文的pdf要指定中 ...

  10. ss client 配置

    1.1安装ss apt-get install python-pippip install shadowsocks 1.2配置ss 新建一个配置文件config.json/etc/shadowsock ...