编解码技术,说白了就是java的序列化,序列化的作用有两个,网络传输和持久化。
随人我们可以使用java提供的序列化方式,netty去传输,但是有很多硬伤,比如java序列化没法跨语言,序列化后码流太大,序列化性能太低等等。
主流的编解码框架有:
Jboss的marshalling包:今天内容
Google的protobuf;
基于protobuf的Kyro;
MessagePack框架(Netty官方支持的框架)等。
marshalling对JDK提供的序列化方式进行了优化,同时又保持了与原生JDK序列化包的兼容性,同时增加了一些可调参数和附加特性。
marshalling的类库:jboss-mashalling-1.3.0和jboss-mashalling-serial-1.3.0。
Jboss的marshalling与Netty结合使用很简单,下面看看小demo:
client:
package cn.lh.netty;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
public class NettyClient {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(MyMarshallingFactory.buildMarshallingDecoder());
ch.pipeline().addLast(MyMarshallingFactory.buildMarshallingEncoder());
ch.pipeline().addLast(new NettyClientHandler());
}
});
ChannelFuture f = bootstrap.connect("127.0.0.1", 8888).sync();
for(int i=1;i<=5;i++){
Request request = new Request();
request.setId(i);
request.setMsg("这是请求内容:"+i);
f.channel().writeAndFlush(request);
}
f.channel().closeFuture().sync();
group.shutdownGracefully();
}
}
NettyClientHandler类:
package cn.lh.netty;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil;
public class NettyClientHandler extends ChannelHandlerAdapter{
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
Response res = (Response) msg;
System.out.println("server response:"+res.getId()+"--"+res.getName());
}finally {
ReferenceCountUtil.release(msg);
}
}
}
MyMarshallingFactory类:
package cn.lh.netty;
import org.jboss.marshalling.MarshallerFactory;
import org.jboss.marshalling.Marshalling;
import org.jboss.marshalling.MarshallingConfiguration;
import io.netty.handler.codec.marshalling.DefaultMarshallerProvider;
import io.netty.handler.codec.marshalling.DefaultUnmarshallerProvider;
import io.netty.handler.codec.marshalling.MarshallerProvider;
import io.netty.handler.codec.marshalling.MarshallingDecoder;
import io.netty.handler.codec.marshalling.MarshallingEncoder;
import io.netty.handler.codec.marshalling.UnmarshallerProvider;
public class MyMarshallingFactory {
public static MarshallingEncoder buildMarshallingEncoder(){
MarshallerFactory factory = Marshalling.getProvidedMarshallerFactory("serial");
MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
MarshallerProvider provider = new DefaultMarshallerProvider(factory, configuration);
MarshallingEncoder encoder = new MarshallingEncoder(provider);
return encoder;
}
public static MarshallingDecoder buildMarshallingDecoder(){
MarshallerFactory factory = Marshalling.getProvidedMarshallerFactory("serial");
MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
UnmarshallerProvider provider = new DefaultUnmarshallerProvider(factory, configuration);
MarshallingDecoder decoder = new MarshallingDecoder(provider);
return decoder;
}
}
Request类:
package cn.lh.netty;
import java.io.Serializable;
public class Request implements Serializable{
private static final long serialVersionUID = 2485854233342015229L;
private int id;
private String msg;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
Response类:
package cn.lh.netty;
import java.io.Serializable;
public class Response implements Serializable{
private static final long serialVersionUID = 3045830684163490285L;
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
NettyServer类:
package cn.lh.netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class NettyServer {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup worker = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boss, worker)
.option(ChannelOption.SO_BACKLOG, 1024)
.option(ChannelOption.SO_KEEPALIVE, true)
.option(ChannelOption.SO_SNDBUF, 32*1024)
.option(ChannelOption.SO_RCVBUF, 32*1024)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(MyMarshallingFactory.buildMarshallingDecoder());
ch.pipeline().addLast(MyMarshallingFactory.buildMarshallingEncoder());
ch.pipeline().addLast(new NettyServerHandler());
}
});
ChannelFuture f = bootstrap.bind(8888).sync();
f.channel().closeFuture().sync();
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
NettyServerHandler类:
package cn.lh.netty;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
public class NettyServerHandler extends ChannelHandlerAdapter{
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Request request = (Request) msg;
System.out.println("client request:"+request.getId()+request.getMsg());
Response res = new Response();
res.setId(request.getId());
res.setName("回应消息"+request.getId());
ctx.channel().writeAndFlush(res);
}
}
输出结果:
client:
server response:1--回应消息1
server response:2--回应消息2
server response:3--回应消息3
server response:4--回应消息4
server response:5--回应消息5
server:
client request:1这是请求内容:1
client request:2这是请求内容:2
client request:3这是请求内容:3
client request:4这是请求内容:4
client request:5这是请求内容:5
注意:这里我在用maven依赖jar包的时候新版本的marshalling的jar包导入不起作用,不发送消息也不报错,搞了半天,可能最新版本的marshalling编解码技术实现改变了,以后在研究,这里使用1.3.0.CR9的jar包即可使用。