netty-netty使用jboss marshalling编解码器
摘自<netty权威指南>
Jboss Marshalling是一个java对象序列化包,对jdk默认的序列化框架进行了优化,又保持了
java.io.Serializable
接口的兼容书书性
引入依赖
<dependency>
<groupId>org.jboss.marshalling</groupId>
<artifactId>jboss-marshalling-serial</artifactId>
<version>2.0.0.Beta2</version>
</dependency>
服务器端
解码器工厂类MarshallingCodeCFactory
:
public class MarshallingCodeCFactory {
public static MarshallingDecoder buildMarshallingDecoder(){
MarshallerFactory factory = Marshalling.getProvidedMarshallerFactory("serial");
MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
UnmarshallerProvider provider
= new DefaultUnmarshallerProvider(factory, configuration);
return new MarshallingDecoder(provider, 1024);
}
public static MarshallingEncoder buildMarshallingEncoder(){
MarshallerFactory factory = Marshalling.getProvidedMarshallerFactory("serial");
MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
MarshallerProvider provider
= new DefaultMarshallerProvider(factory, configuration);
return new MarshallingEncoder(provider);
}
}
public class EchoServer {
private int port;
public EchoServer(int port) {
this.port = port;
}
public static void main(String[] args) throws InterruptedException {
int port = 8080;
new EchoServer(port).start();
}
private void start() throws InterruptedException {
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup work = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(boss, work)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
ch.pipeline().addLast(new SubReqServerHandler());
}
});
ChannelFuture future = b.bind(port);
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()){
System.out.println("server start success...");
}else {
System.out.println("server start failed...");
}
}
});
future.channel().closeFuture().sync();
} finally {
boss.shutdownGracefully();
work.shutdownGracefully();
}
}
}
SubReqServerHandler
:
public class SubReqServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx,
Object msg) throws Exception {
SubscribeReq req = (SubscribeReq) msg;
if ("netty".equalsIgnoreCase(req.getUserName())) {
System.out.println("server recv req[x] : [" + req.toString() + "]");
ctx.writeAndFlush(resp(req.getSubReqID()));
}
}
private SubscribeResp resp(int subReqID) {
SubscribeResp resp = new SubscribeResp();
resp.setSubReqID(subReqID);
resp.setDesc("netty book subscribe success...");
resp.setRespCode(0);
return resp;
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
客户端
public class EchoClient {
private String host;
private int port;
public EchoClient(String host, int port) {
this.host = host;
this.port = port;
}
public static void main(String[] args) throws Exception {
int port = 8080;
String host = "127.0.0.1";
new EchoClient(host, port).connect();
}
private void connect() throws Exception {
EventLoopGroup boss = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(boss)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
ch.pipeline().addLast(new SubReqClientHandler());
}
});
ChannelFuture future = b.connect(host, port).sync();
future.channel().closeFuture().sync();
} finally {
boss.shutdownGracefully();
}
}
}
SubReqClientHandler
:
public class SubReqClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx,
Object msg) throws Exception {
System.out.println("client recv [x]: [" + msg + "]");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
for (int i = 0; i < 10; i++) {
ctx.write(subReq(i));
}
ctx.flush();
}
private SubscribeReq subReq(int i) {
SubscribeReq req = new SubscribeReq();
req.setSubReqID(i);
req.setProductName("netty definitive book");
req.setUserName("netty");
req.setAddress("ShangHai");
return req;
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx)
throws Exception {
ctx.flush();
}
}
运行结果:
server start success...
server recv req[x] : [SubscribeReq{subReqID=0, userName='netty', productName='netty definitive book', address='ShangHai'}]
server recv req[x] : [SubscribeReq{subReqID=1, userName='netty', productName='netty definitive book', address='ShangHai'}]
server recv req[x] : [SubscribeReq{subReqID=2, userName='netty', productName='netty definitive book', address='ShangHai'}]
# client
client recv [x]: [SubscribeResp{subReqID=0, respCode=0, desc='netty book subscribe success...'}]
client recv [x]: [SubscribeResp{subReqID=1, respCode=0, desc='netty book subscribe success...'}]
client recv [x]: [SubscribeResp{subReqID=2, respCode=0, desc='netty book subscribe success...'}]
注意事项
可以发现并没有发生半包的问题,原因是MarshallingDecoder
继承了LengthFieldBasedFrameDecoder
,而LengthFieldBasedFrameDecoder
是用来解决半包问题的:
public class MarshallingDecoder extends LengthFieldBasedFrameDecoder {
...
}