http://cxytiandi.com/blog/detail/17403

上篇文章高性能NIO框架Netty入门篇我们对Netty做了一个简单的介绍,并且写了一个入门的Demo,客户端往服务端发送一个字符串的消息,服务端回复一个字符串的消息,今天我们来学习下在Netty中怎么使用对象来传输数据。

上篇文章中传输字符串我们用的是框架自带的StringEncoder,StringDecoder编解码器,现在想要通过对象来传输数据,该怎么弄呢?

既然StringEncoder和StringDecoder可以传输字符串,我们来看看这2个类的源码不就知道它们到底做了一些什么工作。

StringEncoder

  1. public class StringEncoder extends MessageToMessageEncoder<CharSequence> {
  2. // TODO Use CharsetEncoder instead.
  3. private final Charset charset;
  4. /**
  5. * Creates a new instance with the current system character set.
  6. */
  7. public StringEncoder() {
  8. this(Charset.defaultCharset());
  9. }
  10. /**
  11. * Creates a new instance with the specified character set.
  12. */
  13. public StringEncoder(Charset charset) {
  14. if (charset == null) {
  15. throw new NullPointerException("charset");
  16. }
  17. this.charset = charset;
  18. }
  19. @Override
  20. protected void encode(ChannelHandlerContext ctx, CharSequence msg, List<Object> out) throws Exception {
  21. if (msg.length() == 0) {
  22. return;
  23. }
  24. out.add(ByteBufUtil.encodeString(ctx.alloc(), CharBuffer.wrap(msg), charset));
  25. }
  26. }

通过继承MessageToMessageEncoder,重写encode方法来进行编码操作,就是将字符串进行输出即可。

StringDecoder

  1. public class StringDecoder extends MessageToMessageDecoder<ByteBuf> {
  2. // TODO Use CharsetDecoder instead.
  3. private final Charset charset;
  4. /**
  5. * Creates a new instance with the current system character set.
  6. */
  7. public StringDecoder() {
  8. this(Charset.defaultCharset());
  9. }
  10. /**
  11. * Creates a new instance with the specified character set.
  12. */
  13. public StringDecoder(Charset charset) {
  14. if (charset == null) {
  15. throw new NullPointerException("charset");
  16. }
  17. this.charset = charset;
  18. }
  19. @Override
  20. protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
  21. out.add(msg.toString(charset));
  22. }
  23. }

继承MessageToMessageDecoder,重写decode方法,将ByteBuf数据直接转成字符串进行输出,解码完成。

通过上面的源码分析,我们发现编解码的原理无非就是在数据传输前进行一次处理,接收后进行一次处理,在网络中传输的数据都是字节,我们现在想要传PO对象,那么必然需要进行编码和解码2个步骤,我们可以自定义编解码器来对对象进行序列化,然后通过ByteBuf的形式进行传输, 传输对象需要实现java.io.Serializable接口。

首先我们定义一个传输对象,实现序列化接口,暂时先定义2个字段,一个ID,用来标识客户端,一个内容字段,代码如下:

  1. public class Message implements Serializable {
  2. private static final long serialVersionUID = -7543514952950971498L;
  3. private String id;
  4. private String content;
  5. public String getId() {
  6. return id;
  7. }
  8. public void setId(String id) {
  9. this.id = id;
  10. }
  11. public String getContent() {
  12. return content;
  13. }
  14. public void setContent(String content) {
  15. this.content = content;
  16. }
  17. }

传输对象定好后,定义对象的编解码器。

对象编码器

将对象序列化成字节,通过ByteBuf形式进行传输,ByteBuf是一个byte存放的缓冲区,提供了读写操作。

  1. public class MessageEncoder extends MessageToByteEncoder<Message> {
  2. @Override
  3. protected void encode(ChannelHandlerContext ctx, Message message, ByteBuf out) throws Exception {
  4. byte[] datas = ByteUtils.objectToByte(message);
  5. out.writeBytes(datas);
  6. ctx.flush();
  7. }
  8. }

对象解码器

接收ByteBuf数据,将ByteBuf反序列化成对象

  1. public class MessageDecoder extends ByteToMessageDecoder {
  2. @Override
  3. protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
  4. Object obj = ByteUtils.byteToObject(ByteUtils.read(in));
  5. out.add(obj);
  6. }
  7. }

将上篇文章中服务端的编解码器改成对象编解码器:

  1. public class ImServer {
  2. public void run(int port) {
  3. EventLoopGroup bossGroup = new NioEventLoopGroup();
  4. EventLoopGroup workerGroup = new NioEventLoopGroup();
  5. ServerBootstrap bootstrap = new ServerBootstrap();
  6. bootstrap.group(bossGroup, workerGroup)
  7. .channel(NioServerSocketChannel.class)
  8. .childHandler(new ChannelInitializer<SocketChannel>() {
  9. @Override
  10. public void initChannel(SocketChannel ch) throws Exception {
  11. //实体类传输数据,jdk序列化
  12. ch.pipeline().addLast("decoder", new MessageDecoder());
  13. ch.pipeline().addLast("encoder", new MessageEncoder());
  14. ch.pipeline().addLast(new ServerPoHandler());
  15. //字符串传输数据
  16. /*ch.pipeline().addLast("decoder", new StringDecoder());
  17. ch.pipeline().addLast("encoder", new StringEncoder());
  18. ch.pipeline().addLast(new ServerStringHandler());*/
  19. }
  20. })
  21. .option(ChannelOption.SO_BACKLOG, 128)
  22. .childOption(ChannelOption.SO_KEEPALIVE, true);
  23. try {
  24. ChannelFuture f = bootstrap.bind(port).sync();
  25. f.channel().closeFuture().sync();
  26. } catch (InterruptedException e) {
  27. e.printStackTrace();
  28. } finally {
  29. workerGroup.shutdownGracefully();
  30. bossGroup.shutdownGracefully();
  31. }
  32. }
  33. }

接下来编写服务端的消息处理类:

  1. public class ServerPoHandler extends ChannelInboundHandlerAdapter {
  2. @Override
  3. public void channelRead(ChannelHandlerContext ctx, Object msg) {
  4. Message message = (Message) msg;
  5. System.err.println("server:" + message.getId());
  6. ctx.writeAndFlush(message);
  7. }
  8. @Override
  9. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  10. cause.printStackTrace();
  11. ctx.close();
  12. }
  13. }

服务端改造好了之后,就要改造客户端了,同样的道理,客户端和服务端的编解码器都要一致才行。

客户端连接时指定对象编解码器和对象消息处理类,代码如下:

  1. public class ImConnection {
  2. private Channel channel;
  3. public Channel connect(String host, int port) {
  4. doConnect(host, port);
  5. return this.channel;
  6. }
  7. private void doConnect(String host, int port) {
  8. EventLoopGroup workerGroup = new NioEventLoopGroup();
  9. try {
  10. Bootstrap b = new Bootstrap();
  11. b.group(workerGroup);
  12. b.channel(NioSocketChannel.class);
  13. b.option(ChannelOption.SO_KEEPALIVE, true);
  14. b.handler(new ChannelInitializer<SocketChannel>() {
  15. @Override
  16. public void initChannel(SocketChannel ch) throws Exception {
  17. //实体类传输数据,jdk序列化
  18. ch.pipeline().addLast("decoder", new MessageDecoder());
  19. ch.pipeline().addLast("encoder", new MessageEncoder());
  20. ch.pipeline().addLast(new ClientPoHandler());
  21. //字符串传输数据
  22. /*ch.pipeline().addLast("decoder", new StringDecoder());
  23. ch.pipeline().addLast("encoder", new StringEncoder());
  24. ch.pipeline().addLast(new ClientStringHandler());*/
  25. }
  26. });
  27. ChannelFuture f = b.connect(host, port).sync();
  28. channel = f.channel();
  29. } catch(Exception e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }

客户端消息处理类:

  1. /**
  2. * 当编解码器为实体对象时时用来接收数据
  3. * @author yinjihuan
  4. *
  5. */
  6. public class ClientPoHandler extends ChannelInboundHandlerAdapter {
  7. @Override
  8. public void channelRead(ChannelHandlerContext ctx, Object msg) {
  9. Message message = (Message) msg;
  10. System.out.println("client:" + message.getContent());
  11. }
  12. @Override
  13. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  14. cause.printStackTrace();
  15. ctx.close();
  16. }
  17. }

客户端启动类也需要改造,将发送字符串的消息变成对象消息

  1. public class ImClientApp {
  2. public static void main(String[] args) {
  3. String host = "127.0.0.1";
  4. int port = 2222;
  5. Channel channel = new ImConnection().connect(host, port);
  6. //对象传输数据
  7. Message message = new Message();
  8. message.setId(UUID.randomUUID().toString().replaceAll("-", ""));
  9. message.setContent("hello yinjihuan");
  10. channel.writeAndFlush(message);
  11. //字符串传输数据
  12. //channel.writeAndFlush("yinjihuan");
  13. }
  14. }

源码参考:https://github.com/yinjihuan/netty-im

高性能NIO框架Netty-对象传输的更多相关文章

  1. 高性能NIO框架Netty入门篇

    http://cxytiandi.com/blog/detail/17345 Netty介绍 Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具 ...

  2. 6.高性能NIO框架netty

    1.Netty简介: Netty是基于Java NIO的网络应用框架 Netty是一个NIO client-server(客户端服务器)框架,使用Netty可以快速开发网络应用,例如服务器和客户端协议 ...

  3. 分布式服务框架介绍:最成熟的开源NIO框架Netty

    尽管JDK提供了丰富的NIO类库,网上也有很多NIO学习例程,但是直接使用Java NIO类库想要开发出稳定可靠的通信框架却并非易事,原因如下: 1)NIO的类库和API繁杂,使用麻烦,你需要熟练掌握 ...

  4. Java异步NIO框架Netty实现高性能高并发

    原文地址:http://blog.csdn.net/opengl_es/article/details/40979371?utm_source=tuicool&utm_medium=refer ...

  5. 【Netty】NIO框架Netty入门

    Netty介绍 Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序. 也就是说,Netty ...

  6. Java NIO框架Netty demo

    Netty是什么 Netty是一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序. 也就是说,Netty 是一个基于NI ...

  7. Java NIO框架Netty教程(一) – Hello Netty

    先啰嗦两句,如果你还不知道Netty是做什么的能做什么.那可以先简单的搜索了解一下.我只能说Netty是一个NIO的框架,可以用于开发分布式的Java程序.具体能做什么,各位可以尽量发挥想象.技术,是 ...

  8. Java NIO框架Netty课程(一) – Hello Netty

    首先啰嗦2,假如你不知道Netty怎么办怎么办.它可以是一个简单的搜索,找出.我只能说Netty是NIO该框架,它可用于开发分布式Java计划.详细情况可以做,我们可以尝试用你的想象力. 技术,它是服 ...

  9. NIO高性能框架-Netty

    一:Netty是什么 ? Netty是目前最流行的由JBOSS提供的一个Java开源框架NIO框架,Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客 ...

随机推荐

  1. windows版本下ELK配置

    windows版本的es和kibana相对配置起来很简单,网上已经有很多例子都是正确的,只需按照步骤安装一下即可. 主要logstash,网上说的方案,大都不能配置成功,或者总有一些错误,下面把我自己 ...

  2. bat实现获取文件每行内容,for循环中运行多条命令

    关键词:bat,bat获取文件内容 1.获取每行内容 @echo offfor /f "delims=" %%i in (config.txt) do (echo "%% ...

  3. zabbix 3.2源码安装

    环境: centos7.2 nginx 1.10.3 mysql 5.5.38 php 5.5.38 一.zabbix介绍 1.Zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企 ...

  4. 卸载postgresql数据库

    卸载postgresql数据库有两种方法,第一种一个个包卸载,第二种全部卸载.做这些之前请先做好备份,以防意外! 1.1.查询出postgres数据库,用命令rpm -qa |grep postgre ...

  5. Vagrant测试

    载新的BOX实现虚拟机恢复.效果如下:(可用linux命令操作,但是很多时候我们还是需要图形化界面,不然不利于开发代码编写) 参考PDF中的记录网址http://www.vagrantbox.es/ ...

  6. APK反编译、重编译、签名、查看源码

    1.反编译与重编译 工具:apktool 下载地址:https://ibotpeaches.github.io/Apktool/ 环境:Java (JRE 1.7) 安装步骤:参考官网(也可以不安装, ...

  7. 安装setuptools

    1.下载地址:https://pypi.python.org/pypi/setuptools 2.这是一个压缩文件,将其解压到安装目录,并进入该文件夹,按住shift键后,在文件夹空白处点击鼠标右键, ...

  8. python基础(9)-迭代器&生成器函数&生成器进阶&推导式

    迭代器 可迭代协议和迭代器协议 可迭代协议 只要含有__iter__方法的对象都是可迭代的 迭代器协议 内部含有__next__和__iter__方法的就是迭代器 关系 1.可以被for循环的都是可迭 ...

  9. ABP-添加表

    1.在My_ABP.Core根目录下先创建一个文件夹,在该文件夹里创建一个公共的类,在里面定义所需要用到的属性 public class Person:Entity      {         pu ...

  10. python中的下划线

    在学习Python的时候,会不理解为什么在方法(method)前面会加好几个下划线,有时甚至两边都会加.在Python中下划线还具有 private 和 protected 类似的访问权限作用,下面我 ...