Netty编解码技术
编解码技术,说白了就是java序列化技术,序列化目的就两个,第一进行网络传输,第二对象持久化。
虽然可以使用java进行对象序列化,netty去传输,但是java序列化的硬伤太多,比如java序列化没法跨语言、序列化后码流太大、序列化性能太低等等。。
主流的编解码框架:
- JBoss的Marshalling包
- google的Protobuf
- 基于Protobuf的Kyro
- MessagePack框架
Jboss Marshalling是一个java对象序列化包,对JDK默认的序列化框架进行了优化,但又保持跟java.io.Serializable接口的兼容,同时增加了一些可调的参数和附加特性。
将对象编解码后传传输
Req
public class Req implements Serializable{
private static final long SerialVersionUID = 1L;
private String id;
private String name;
private String requestMessage;
private byte[] attachment;
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;
}
public byte[] getAttachment() {
return attachment;
}
public void setAttachment(byte[] attachment) {
this.attachment = attachment;
}
}
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;
}
}
MarshallingCodeFactory.class
public class MarshallingCodeFactory {
/**
* 创建Marshalling解码器MarshallingDecoder
* @return
*/
public static MarshallingDecoder buildMarshallingDecoder(){
//首先通过Marshalling工具类的精通方法获取Marshalling实例对象 多数Serial标志创建的是java序列化工厂对象
final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
//创建了MarshallingConfiguration对象,配置的版本号为5
final MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
//根据marshallingFactory和Configuration创建provider
UnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, configuration);
//构建Netty的MarshallingDecoder对象,两个参数分别为Provider和单个消息序列化后的最大长度
MarshallingDecoder decoder = new MarshallingDecoder(provider,1024*1024*1);
return decoder;
}
/**
* 创建MarshallingEncoder
* @return
*/
public static MarshallingEncoder buildMarshallingEncoder(){
//首先通过Marshalling工具类的精通方法获取Marshalling实例对象 多数Serial标志创建的是java序列化工厂对象
final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
//创建了MarshallingConfiguration对象,配置的版本号为5
final MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
//根据marshallingFactory和Configuration创建provider
MarshallerProvider provider = new DefaultMarshallerProvider(marshallerFactory, configuration);
//构建Netty的MarshallingEncoder对象,MarshallingEncoder用于实现序列化接口的POJO对象序列化为二进制数组
MarshallingEncoder encoder = new MarshallingEncoder(provider);
return encoder;
}
}
Client.java
public class Client {
public static void main(String[] args) throws Exception {
NioEventLoopGroup group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
//设置日志
.handler(new LoggingHandler(LogLevel.INFO))
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
sc.pipeline().addLast(MarshallingCodeFactory.buildMarshallingDecoder());
sc.pipeline().addLast(MarshallingCodeFactory.buildMarshallingEncoder());
sc.pipeline().addLast(new ClientHandler());
}
});
ChannelFuture cf = b.connect("127.0.0.1",8765).sync();
for(int i=0;i<5;i++){
Req req = new Req();
req.setId(""+i);
req.setName("pro"+i);
req.setRequestMessage("数据信息"+i);
//读取文件
String readPath = System.getProperty("user.dir") + File.separatorChar + "sources" + File.separatorChar + "001.jpg";
File file = new File(readPath);
FileInputStream in = new FileInputStream(file);
byte[] data = new byte[in.available()];
in.read(data);
in.close();
req.setAttachment(GzipUtil.gzip(data));
cf.channel().writeAndFlush(req);
}
cf.channel().closeFuture().sync();
group.shutdownGracefully();
}
}
ClientHandler.java
public class ClientHandler extends ChannelHandlerAdapter{
@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);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
ctx.close();
}
}
Server.java
public class Server {
public static void main(String[] args) throws InterruptedException {
NioEventLoopGroup pGroup = new NioEventLoopGroup();
NioEventLoopGroup cGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(pGroup,cGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
sc.pipeline().addLast(MarshallingCodeFactory.buildMarshallingDecoder());
sc.pipeline().addLast(MarshallingCodeFactory.buildMarshallingEncoder());
sc.pipeline().addLast(new ServerHandler());
}
});
ChannelFuture cf = b.bind(8765).sync();
cf.channel().closeFuture().sync();
pGroup.shutdownGracefully();
cGroup.shutdownGracefully();
}
}
ServerHandler.java
public class ServerHandler extends ChannelHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
Req req =(Req)msg;
System.out.println("Server:"+req.getId()+","+req.getName()+","+req.getRequestMessage());
byte[] attachment = GzipUtil.ungzip(req.getAttachment());
String path = System.getProperty("user.dir")+File.separatorChar+"receive"+File.separatorChar+"001.jpg";
FileOutputStream fos = new FileOutputStream(path);
fos.write(attachment);
fos.close();
Resp resp = new Resp();
resp.setId(req.getId());
resp.setName("resp"+req.getId());
resp.setResponseMessage("响应内容"+req.getId());
ctx.writeAndFlush(resp);
}
}