前面讲了netty解决拆包粘包的问题
我们发现拆包粘包问题的解决都只是解决netty发送字符串的情况
在企业及开发中很少有直接使用字符串的,一般都有定义好的消息体,这个消息体一定对应实体类
如果要传送实体类那么久一定要对实体类做序列化
(序列化就是把文件或者内存中的数据结构转换为字节数组以便存储或在网路传输)
今天就介绍一下jboss的marshalling序列化框架
下面文章是听了白老师的Netty教程写的,发现网上这段代码很多,
反而是Marshalling并没有太多的介绍,有时间研究一下Marshalling并把链接贴在这儿
下面的代码地址 https://github.com/lyzxhero/Netty/tree/dev
server端代码
package com.lyzx.netty.netty04;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @author hero.li
* netty编解码之Marshalling
*/
public class Server {
public static void main(String[] args) throws InterruptedException {
//开启两个线程组,一个用于接受客户端的请求 另一个用于异步的网络IO的读写
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
//Netty启动的辅助类 里面封装了客户端和服务端的链接以及如何处理选择器 selector等逻辑
ServerBootstrap b = new ServerBootstrap();
//传入两个线程组,设置传输块大小为1k,添加ServerHandler类型的过滤器(表示如何处理这些消息,过滤器当然要集成netty的一个接口)
b.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,1024)
.childOption(ChannelOption.SO_KEEPALIVE,Boolean.TRUE)
.childHandler(new ChannelInitializer(){
@Override
protected void initChannel(SocketChannel ch) throws Exception{
ChannelHandler[] arr = {MarshallingCodeCFactory.marshallingDecoder(),
MarshallingCodeCFactory.marshallingEncoder(),
new ServerHandler()};
ch.pipeline().addLast(arr);
}
});
//同步等待绑定端口结束
ChannelFuture f = b.bind(9988).sync();
//等待服务端监听端口关闭
f.channel().closeFuture().sync();
//优雅的关闭线程组
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
server Handler代码
package com.lyzx.netty.netty04;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* 对于网事件做读写,通常只要关注channelRead()和exceptionCaught()即可
*/
public class ServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("server:channelRead____通道可读开始");
NettyRequest nr = (NettyRequest)msg;
System.out.println("server:收到的消息____:"+nr);
String datetime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS"));
nr.setMsg(datetime);
ctx.channel().writeAndFlush(nr);
System.out.println("server:channelRead____通道可读结束");
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("server:channelReadComplete____通道可读完成 ");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("server:exceptionCaught____发生异常");
ctx.close();
}
}
client端代码
package com.lyzx.netty.netty04;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
public class Client {
public static void main(String[] args) throws InterruptedException {
NioEventLoopGroup group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY,true)
.handler(new ChannelInitializer(){
@Override
protected void initChannel(SocketChannel ch) throws Exception{
ChannelHandler[] arr = {MarshallingCodeCFactory.marshallingDecoder(),
MarshallingCodeCFactory.marshallingEncoder(),
new ClientHandler()};
ch.pipeline().addLast(arr);
}
});
ChannelFuture f = b.connect("127.0.0.1", 9988).sync();
f.channel().closeFuture().sync();
group.shutdownGracefully();
}
}
clienthandler代码
package com.lyzx.netty.netty04;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class ClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("client:channelActive____通道激活开始");
for(int i=0;i<20;i++){
NettyRequest req = new NettyRequest();
req.setId((long)i);
req.setMsg("data_"+i);
ctx.channel().writeAndFlush(req);
System.out.println("..."+req);
}
System.out.println("client:channelActive____通道激活结束");
}
@Override
public void channelRead(ChannelHandlerContext ctx,Object msg) throws Exception {
System.out.println("client____:通道可读开始");
NettyRequest nr = (NettyRequest)msg;
System.out.println("client____response time:"+nr);
System.out.println("client____:通道可读结束");
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("client:通道可读完成");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("client:发生异常");
}
}
其他工具类
package com.lyzx.netty.netty04;
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;
import org.jboss.marshalling.MarshallerFactory;
import org.jboss.marshalling.Marshalling;
import org.jboss.marshalling.MarshallingConfiguration;
/**
* Marshalling工厂
* @author(alienware)
* @since 2014-12-16
*/
public final class MarshallingCodeCFactory {
/**
* 创建Jboss Marshalling解码器MarshallingDecoder
* @return MarshallingDecoder
*/
public static MarshallingDecoder marshallingDecoder() {
//首先通过Marshalling工具类的方法获取Marshalling实例对象 参数serial标识创建的是java序列化工厂对象。
final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
//创建了MarshallingConfiguration对象,配置了版本号为5
final MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
//根据marshallerFactory和configuration创建provider
UnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, configuration);
//构建Netty的MarshallingDecoder对象,俩个参数分别为provider和单个消息序列化后的最大长度
MarshallingDecoder decoder = new MarshallingDecoder(provider, 1024 * 1024 * 1);
return decoder;
}
/**
* 创建Jboss Marshalling编码器MarshallingEncoder
* @return MarshallingEncoder
*/
public static MarshallingEncoder marshallingEncoder() {
final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
final MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
MarshallerProvider provider = new DefaultMarshallerProvider(marshallerFactory, configuration);
//构建Netty的MarshallingEncoder对象,MarshallingEncoder用于实现序列化接口的POJO对象序列化为二进制数组
MarshallingEncoder encoder = new MarshallingEncoder(provider);
return encoder;
}
}
package com.lyzx.netty.netty04;
import java.io.Serializable;
public class NettyRequest implements Serializable {
private Long id;
private int code;
private String msg;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
@Override
public String toString() {
return "NettyRequest{" +
"id=" + id +
", code=" + code +
", msg='" + msg + '\'' +
'}';
}
}