高性能NIO框架Netty-对象传输
http://cxytiandi.com/blog/detail/17403
上篇文章高性能NIO框架Netty入门篇我们对Netty做了一个简单的介绍,并且写了一个入门的Demo,客户端往服务端发送一个字符串的消息,服务端回复一个字符串的消息,今天我们来学习下在Netty中怎么使用对象来传输数据。
上篇文章中传输字符串我们用的是框架自带的StringEncoder,StringDecoder编解码器,现在想要通过对象来传输数据,该怎么弄呢?
既然StringEncoder和StringDecoder可以传输字符串,我们来看看这2个类的源码不就知道它们到底做了一些什么工作。
StringEncoder
public class StringEncoder extends MessageToMessageEncoder<CharSequence> {// TODO Use CharsetEncoder instead.private final Charset charset;/*** Creates a new instance with the current system character set.*/public StringEncoder() {this(Charset.defaultCharset());}/*** Creates a new instance with the specified character set.*/public StringEncoder(Charset charset) {if (charset == null) {throw new NullPointerException("charset");}this.charset = charset;}@Overrideprotected void encode(ChannelHandlerContext ctx, CharSequence msg, List<Object> out) throws Exception {if (msg.length() == 0) {return;}out.add(ByteBufUtil.encodeString(ctx.alloc(), CharBuffer.wrap(msg), charset));}}
通过继承MessageToMessageEncoder,重写encode方法来进行编码操作,就是将字符串进行输出即可。
StringDecoder
public class StringDecoder extends MessageToMessageDecoder<ByteBuf> {// TODO Use CharsetDecoder instead.private final Charset charset;/*** Creates a new instance with the current system character set.*/public StringDecoder() {this(Charset.defaultCharset());}/*** Creates a new instance with the specified character set.*/public StringDecoder(Charset charset) {if (charset == null) {throw new NullPointerException("charset");}this.charset = charset;}@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {out.add(msg.toString(charset));}}
继承MessageToMessageDecoder,重写decode方法,将ByteBuf数据直接转成字符串进行输出,解码完成。
通过上面的源码分析,我们发现编解码的原理无非就是在数据传输前进行一次处理,接收后进行一次处理,在网络中传输的数据都是字节,我们现在想要传PO对象,那么必然需要进行编码和解码2个步骤,我们可以自定义编解码器来对对象进行序列化,然后通过ByteBuf的形式进行传输, 传输对象需要实现java.io.Serializable接口。
首先我们定义一个传输对象,实现序列化接口,暂时先定义2个字段,一个ID,用来标识客户端,一个内容字段,代码如下:
public class Message implements Serializable {private static final long serialVersionUID = -7543514952950971498L;private String id;private String content;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}}
传输对象定好后,定义对象的编解码器。
对象编码器
将对象序列化成字节,通过ByteBuf形式进行传输,ByteBuf是一个byte存放的缓冲区,提供了读写操作。
public class MessageEncoder extends MessageToByteEncoder<Message> {@Overrideprotected void encode(ChannelHandlerContext ctx, Message message, ByteBuf out) throws Exception {byte[] datas = ByteUtils.objectToByte(message);out.writeBytes(datas);ctx.flush();}}
对象解码器
接收ByteBuf数据,将ByteBuf反序列化成对象
public class MessageDecoder extends ByteToMessageDecoder {@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {Object obj = ByteUtils.byteToObject(ByteUtils.read(in));out.add(obj);}}
将上篇文章中服务端的编解码器改成对象编解码器:
public class ImServer {public void run(int port) {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();ServerBootstrap bootstrap = new ServerBootstrap();bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {//实体类传输数据,jdk序列化ch.pipeline().addLast("decoder", new MessageDecoder());ch.pipeline().addLast("encoder", new MessageEncoder());ch.pipeline().addLast(new ServerPoHandler());//字符串传输数据/*ch.pipeline().addLast("decoder", new StringDecoder());ch.pipeline().addLast("encoder", new StringEncoder());ch.pipeline().addLast(new ServerStringHandler());*/}}).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);try {ChannelFuture f = bootstrap.bind(port).sync();f.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();} finally {workerGroup.shutdownGracefully();bossGroup.shutdownGracefully();}}}
接下来编写服务端的消息处理类:
public class ServerPoHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) {Message message = (Message) msg;System.err.println("server:" + message.getId());ctx.writeAndFlush(message);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace();ctx.close();}}
服务端改造好了之后,就要改造客户端了,同样的道理,客户端和服务端的编解码器都要一致才行。
客户端连接时指定对象编解码器和对象消息处理类,代码如下:
public class ImConnection {private Channel channel;public Channel connect(String host, int port) {doConnect(host, port);return this.channel;}private void doConnect(String host, int port) {EventLoopGroup workerGroup = new NioEventLoopGroup();try {Bootstrap b = new Bootstrap();b.group(workerGroup);b.channel(NioSocketChannel.class);b.option(ChannelOption.SO_KEEPALIVE, true);b.handler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {//实体类传输数据,jdk序列化ch.pipeline().addLast("decoder", new MessageDecoder());ch.pipeline().addLast("encoder", new MessageEncoder());ch.pipeline().addLast(new ClientPoHandler());//字符串传输数据/*ch.pipeline().addLast("decoder", new StringDecoder());ch.pipeline().addLast("encoder", new StringEncoder());ch.pipeline().addLast(new ClientStringHandler());*/}});ChannelFuture f = b.connect(host, port).sync();channel = f.channel();} catch(Exception e) {e.printStackTrace();}}}
客户端消息处理类:
/*** 当编解码器为实体对象时时用来接收数据* @author yinjihuan**/public class ClientPoHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) {Message message = (Message) msg;System.out.println("client:" + message.getContent());}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace();ctx.close();}}
客户端启动类也需要改造,将发送字符串的消息变成对象消息
public class ImClientApp {public static void main(String[] args) {String host = "127.0.0.1";int port = 2222;Channel channel = new ImConnection().connect(host, port);//对象传输数据Message message = new Message();message.setId(UUID.randomUUID().toString().replaceAll("-", ""));message.setContent("hello yinjihuan");channel.writeAndFlush(message);//字符串传输数据//channel.writeAndFlush("yinjihuan");}}
源码参考:https://github.com/yinjihuan/netty-im
高性能NIO框架Netty-对象传输的更多相关文章
- 高性能NIO框架Netty入门篇
http://cxytiandi.com/blog/detail/17345 Netty介绍 Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具 ...
- 6.高性能NIO框架netty
1.Netty简介: Netty是基于Java NIO的网络应用框架 Netty是一个NIO client-server(客户端服务器)框架,使用Netty可以快速开发网络应用,例如服务器和客户端协议 ...
- 分布式服务框架介绍:最成熟的开源NIO框架Netty
尽管JDK提供了丰富的NIO类库,网上也有很多NIO学习例程,但是直接使用Java NIO类库想要开发出稳定可靠的通信框架却并非易事,原因如下: 1)NIO的类库和API繁杂,使用麻烦,你需要熟练掌握 ...
- Java异步NIO框架Netty实现高性能高并发
原文地址:http://blog.csdn.net/opengl_es/article/details/40979371?utm_source=tuicool&utm_medium=refer ...
- 【Netty】NIO框架Netty入门
Netty介绍 Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序. 也就是说,Netty ...
- Java NIO框架Netty demo
Netty是什么 Netty是一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序. 也就是说,Netty 是一个基于NI ...
- Java NIO框架Netty教程(一) – Hello Netty
先啰嗦两句,如果你还不知道Netty是做什么的能做什么.那可以先简单的搜索了解一下.我只能说Netty是一个NIO的框架,可以用于开发分布式的Java程序.具体能做什么,各位可以尽量发挥想象.技术,是 ...
- Java NIO框架Netty课程(一) – Hello Netty
首先啰嗦2,假如你不知道Netty怎么办怎么办.它可以是一个简单的搜索,找出.我只能说Netty是NIO该框架,它可用于开发分布式Java计划.详细情况可以做,我们可以尝试用你的想象力. 技术,它是服 ...
- NIO高性能框架-Netty
一:Netty是什么 ? Netty是目前最流行的由JBOSS提供的一个Java开源框架NIO框架,Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客 ...
随机推荐
- ul+li水平居中的几种方法
一.posotion:relative; 代码: <!DOCTYPE html> <html> <head> <meta charset="UTF- ...
- PinyinUtil
import java.util.HashSet;import java.util.Set;import java.util.regex.Matcher;import java.util.regex. ...
- Centos7 下 yum -y install ntp 出现/var/run/yum.pid 已被锁定
[root@localhost ~ ]# yum -y install ntp已加载插件:fastestmirror, langpacksRepodata is over 2 weeks old. I ...
- PHP递归方法实现前序、中序、后序遍历二叉树
二叉树是每个节点最多有两个子树的树结构.通常子树被称作“左子树”(left subtree)和“右子树”(right subtree). class Node { public $value; pub ...
- 231A
#include <iostream> using namespace std; #define maxSize 10 int main() { int views[maxSize]; i ...
- Openresty 安装第三方插件
Openresty 安装第三方插件 程序媛没有夜生活 2016.08.02 15:33* 字数 167 阅读 1283评论 0喜欢 2 在安装之前,我们先来看一下我们现有的模块. 1.将需要安装的插件 ...
- windows 邮槽mailslot 在服务程序内建立后客户端无权限访问(GetLastError() == 5)的问题
邮槽创建在服务程序内,可以创建成功, 但外部客户端连接时 m_hMailslot = CreateFile("\\\\.\\mailslot\\zdpMailslot",GENER ...
- git 不区分文件大小写的处理
- 回车和刷新以及Ctr+F5的区别
回车(url跳转)主要是判断本地缓存文件的Expires的有效时间,如果有效则直接使用客户端缓存 不在提交到HTTP服务器 F5 Expires设置不再起效果,只有Last-Modified/ETag ...
- 49.CSS--- 特殊css3效果展示
1.设置多行文本超出显示省略号<div class="caption"> <p>显示超过两行就显示省略号,其余隐藏,隐藏不了的情况下给这个模块添加一个高度和 ...