java网络编程之Netty编解码技术(六)
2017-11-24 16:48
459 查看
java网络编程之Netty编解码技术(六)
概念理解
编解码技术,说白了就是Java序列化技术,序列化目的就两个,第一进行网络传输,第二对象持久化。虽然我们可以使用java进行对象序列化,Netty去传输,但是Java序列化的硬伤太多,比如Java序列化没法跨语言、序列化后码流太大、序列化性能太低等等。JBoss Marshalling序列化的速度是JDK的3倍。主流的编解码框架:
1、JBoss的Marshalling包
2、Google的Protobuf
3、基于 Protobuf 的Kyro
4、MessagePack框架
每个编解码的框架都不难,下面我主要是通过JBoss来讲解,需要了解其他框架的可以去百度。
JBoos Marshalling
JBoos Marshalling是一个java对象系列化的包,对JDK默认的序列化框架进行了优化,但又保持跟java.io.Serializable接口的兼容,同时增加了一些可调的参数和附加特征。类库:jboss-marshalling-1.3.0 jboss-marshalling-serial-1.3.0
下载地址:https://www.jboss.org/jbossmarshalling/downloads
JBoos Marshalling与Netty结合后进行序列化对象的代码编写非常简单,下面我会一一介绍。
[b]实体类[/b]
首先,需要两个实体类,实体类都需要实现Serializable接口,Req类是用来做客户端的请求的, Resp类是用来做服务端返回给客户端的响应。
Req类代码如下:
public class Req implements Serializable{ private static final long SerialVersionUID = 1L; private String id ; private String name ; private String requestMessage ; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRequestMessage() { return requestMessage; } public void setRequestMessage(String requestMessage) { this.requestMessage = requestMessage; } }
Resp类代码如下:
public class Resp implements Serializable{ private static final long serialVersionUID = 1L; private String id; private String name; private String responseMessage; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getResponseMessage() { return responseMessage; } public void setResponseMessage(String responseMessage) { this.responseMessage = responseMessage; } }
这里代码没什么好说的
[b]Jboss Marshalling 编解码工具类[/b]
在编写之前必须先导入Jboss需要的包
public final class MarshallingCodeCFactory { /** * 创建Jboss Marshalling解码器MarshallingDecoder * @return MarshallingDecoder */ public static MarshallingDecoder buildMarshallingDecoder() { //1 final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial"); //2 final MarshallingConfiguration configuration = new MarshallingConfiguration(); configuration.setVersion(5); //3 UnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, configuration); //4 MarshallingDecoder decoder = new MarshallingDecoder(provider, 1024 * 1024 * 1); return decoder; } /** * 创建Jboss Marshalling编码器MarshallingEncoder * @return MarshallingEncoder */ public static MarshallingEncoder buildMarshallingEncoder() { final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial"); final MarshallingConfiguration configuration = new MarshallingConfiguration(); configuration.setVersion(5); MarshallerProvider provider = new DefaultMarshallerProvider(marshallerFactory, configuration); //5 MarshallingEncoder encoder = new MarshallingEncoder(provider); return encoder; } }
1、首先通过Marshalling工具类的精通方法获取Marshalling实例对象 参数serial标识创建的是java序列化工厂对象。
2、创建了MarshallingConfiguration对象,配置了版本号为5
3、根据marshallerFactory和configuration创建provider
4、构建Netty的MarshallingDecoder对象,俩个参数分别为provider和单个消息序列化后的最大长度
5、构建Netty的MarshallingEncoder对象,MarshallingEncoder用于实现序列化接口的POJO对象序列化为二进制数组
个人感觉不难都是一些固定的写法,记住每一步要做什么就好。
[b]服务端[/b]
public class Server { public static void main(String[] args) throws Exception{ EventLoopGroup pGroup = new NioEventLoopGroup(); EventLoopGroup cGroup = new NioEventLoopGroup(); ServerBootstrap b = new ServerBootstrap(); b.group(pGroup, cGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 1024) //1 .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer<SocketChannel>() { protected void initChannel(SocketChannel sc) throws Exception { //2 sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder()); //3 sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder()); sc.pipeline().addLast(new ServerHandler()); } }); ChannelFuture cf = b.bind(8765).sync(); cf.channel().closeFuture().sync(); pGroup.shutdownGracefully(); cGroup.shutdownGracefully(); } }
这里其实没什么改动,跟我上一篇文章的Netty流数据的传输处理差不多,
1、设置日志(这里需要自己导入log4j.jar) 当然你也可以不设置打印日记
2、这是我们写的Jboss Marshalling工具类的解码器MarshallingDecoder
3、这是我们写的Jboss Marshalling工具类的编码器MarshallingEncoder
其它代码说明可以去看我的Netty第一个程序的那篇文章。
[b]服务端业务处理[/b]
public class ServerHandler extends ChannelHandlerAdapter{ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Req req = (Req)msg; System.out.println("Server : " + req.getId() + ", " + req.getName() + ", " + req.getRequestMessage()); Resp resp = new Resp(); resp.setId(req.getId()); resp.setName("resp" + req.getId()); resp.setResponseMessage("响应内容" + req.getId()); ctx.writeAndFlush(resp);//.addListener(ChannelFutureListener.CLOSE); } }
这里业务逻辑主要是将客户端传过来的信息进行打印,然后将数据传入返回的实体类Resp,将实体类Resp返回给客户端
[b]客户端[/b]
public class Client { public static void main(String[] args) throws Exception{ EventLoopGroup group = new NioEventLoopGroup(); Bootstrap b = new Bootstrap(); b.group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel sc) throws Exception { //1 解码 sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder()); //2 编码 sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder()); sc.pipeline().addLast(new ClientHandler()); } }); ChannelFuture cf = b.connect("127.0.0.1", 8765).sync(); //3 for(int i = 0; i < 5; i++ ){ Req req = new Req(); req.setId("" + i); req.setName("pro" + i); req.setRequestMessage("数据信息" + i); cf.channel().writeAndFlush(req); } cf.channel().closeFuture().sync(); group.shutdownGracefully(); } }
这里编解码跟服务端一样,不再详细说,不懂可以回头看看服务端的。
3、for循环向服务端发送五条消息
[b]客户端业务处理[/b]
public class ClientHandler extends ChannelHandlerAdapter{ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { try { Resp resp = (Resp)msg; System.out.println("Client : " + resp.getId() + ", " + resp.getName() + ", " + resp.getResponseMessage()); } finally { ReferenceCountUtil.release(msg); } } }
这里很简单,没什么好说的了。
好!到这目前所有代码都编写完了来测试一下效果。
服务端启动打印如图:
客户端启动打印如图:
客户端启动后服务端的打印:
源代码:https://github.com/hfbin/Thread_Socket/tree/master/Socket/serializable
相关文章推荐
- java技术之网络编程
- Java网络编程——远程通讯可选技术及原理
- Java网络编程丶数据库编程丶XML解析技术。
- Java网络编程-对象编解码方案、优劣对照
- Java基本概念-网络编程和反射技术
- Java高手真经. 编程基础卷:Java核心编程技术:Java基础+核心库+图形+网络+高级特性
- java 网络 socket编程 Java核心技术读书笔记
- Java IO、网络编程、NIO、Netty、Hessian、RPC、RMI的学习路线
- Java网络编程之Netty拆包和黏包-yellowcong
- Java网络编程----Netty入门(NIO框架)
- java网络编程之Netty第一个程序(四)
- 利用Java技术开发Web网络课件浅议-Java基础-Java-编程开发
- Netty学习-Java网络编程
- 23.JAVA核心技术-网络编程
- Java网络编程-对象编解码方案、优劣对比
- Netty in Action (二)第一章节 第一部分 java网络编程
- 网络编程 -- RPC实现原理 -- Netty -- 迭代版本V3 -- 编码解码
- Java网络编程-对象编解码方案、优劣对比
- 黑马程序员--java技术blog---第八篇:网络编程(1)