netty(二)–使用Marshalling編解碼java對象
文章目錄
一、簡介
marshalling是jboss的java對象序列化包,修正了jdk原生序列化存在的問題,保持了對java.io.Serializable接口的兼容,這裏介紹以marshalling爲編解碼工具在netty中的使用。
二、代碼示例
2.1 添加maven依賴
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>5.0.0.Alpha2</version>
</dependency>
<dependency>
<groupId>org.jboss.marshalling</groupId>
<artifactId>jboss-marshalling-serial</artifactId>
<version>2.0.6.Final</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.46</version>
</dependency>
2.2 定義消息對象
package com.dragon.study.netty;
import lombok.Data;
import java.io.Serializable;
@Data
public class Msg implements Serializable {
private String id;
private String content;
public Msg(String id, String content) {
this.id = id;
this.content = content;
}
}
2.3 定義marshalling編解碼工具
package com.dragon.study.netty;
import io.netty.handler.codec.marshalling.*;
import org.jboss.marshalling.MarshallerFactory;
import org.jboss.marshalling.Marshalling;
import org.jboss.marshalling.MarshallingConfiguration;
public class MarshallingFactory {
//生成Marshalling工廠類
private static MarshallerFactory mf = Marshalling.getProvidedMarshallerFactory("serial");
private static MarshallingConfiguration conf = new MarshallingConfiguration();
//解碼器
private static MarshallingDecoder decoder;
//編碼器
private static MarshallingEncoder encoder;
static{
//設置版本
conf.setVersion(5);
UnmarshallerProvider upr = new DefaultUnmarshallerProvider(mf, conf);
decoder = new MarshallingDecoder(upr, 1024);
MarshallerProvider pr = new DefaultMarshallerProvider(mf, conf);
encoder = new MarshallingEncoder(pr);
}
//生成編碼器
public static MarshallingEncoder getEncoder(){
return encoder;
}
//生成編碼器
public static MarshallingDecoder getDecoder(){
return decoder;
}
}
2.4 定義服務端
package com.dragon.study.netty;
import com.alibaba.fastjson.JSON;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.util.Scanner;
public class NettyMarshallingServerMain {
public static void main(String[] args) throws Exception {
int port = 7001;
//主線程組,接收網絡請求
EventLoopGroup bossGroup = new NioEventLoopGroup();
//worker線程組,對接收到的請求進行讀寫處理
EventLoopGroup workerGroup = new NioEventLoopGroup();
//啓動服務的啓動類(輔助類)
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup) // 添加主線程組和worker線程組
.channel(NioServerSocketChannel.class) //設置channel爲服務端NioServerSocketChannel
.childHandler(new ChannelInitializer<NioSocketChannel>() { //綁定io事件處理類
@Override
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
ChannelPipeline pipeline = nioSocketChannel.pipeline();
//設置編解碼
pipeline.addLast(MarshallingFactory.getEncoder());
pipeline.addLast(MarshallingFactory.getDecoder());
pipeline.addLast(new IODisposeHandler()); //添加io處理器
}
})
.option(ChannelOption.SO_BACKLOG, 128) //設置日誌
.option(ChannelOption.SO_SNDBUF, 32 * 1024) //設置發送緩存
.option(ChannelOption.SO_RCVBUF, 32 * 1024) //接收緩存
.childOption(ChannelOption.SO_KEEPALIVE, true); //是否保持連接
//綁定端口,同步等待成功
ChannelFuture future = bootstrap.bind(port).sync();
System.out.println("服務啓動,等待連接");
//關閉監聽端口,同步等待
future.channel().closeFuture().sync();
//退出,釋放線程資源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
/**
* io事件處理
*/
static class IODisposeHandler extends ChannelHandlerAdapter {
WriteThread writeThread;
/**
* 建立連接
*
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("收到連接:" + ctx.channel());
//新起寫數據線程
writeThread = new WriteThread(ctx);
writeThread.start();
}
/**
* 消息讀取
*
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Msg m = (Msg) msg;
System.out.println("server receive msg:" + JSON.toJSONString(m));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("連接出錯");
writeThread.runFlag = false;
ctx.close();
}
}
/**
* 寫數據線程
*/
static class WriteThread extends Thread {
ChannelHandlerContext ctx;
//線程關閉標誌位
volatile boolean runFlag = true;
public WriteThread(ChannelHandlerContext ctx) {
this.ctx = ctx;
}
@Override
public void run() {
try {
Scanner scanner = new Scanner(System.in);
while (runFlag) {
System.out.print("server send msg:");
String msg = scanner.nextLine();
Msg m = new Msg("two", msg);
//發送數據
ctx.channel().writeAndFlush(m);
}
} catch (Exception e) {
}
}
}
}
2.5 定義客戶端
package com.dragon.study.netty;
import com.alibaba.fastjson.JSON;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.util.Scanner;
public class NettyMarshallingClientMain {
public static void main(String[] args) throws Exception {
EventLoopGroup workerGroup = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(workerGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
ChannelPipeline pipeline = nioSocketChannel.pipeline();
//設置編解碼
pipeline.addLast(MarshallingFactory.getEncoder());
pipeline.addLast(MarshallingFactory.getDecoder());
pipeline.addLast(new IODisposeHandler());//添加io處理器
}
});
ChannelFuture future = bootstrap.connect("127.0.0.1", 7001).sync();
future.channel().closeFuture().sync();
workerGroup.shutdownGracefully();
}
/**
* io事件處理
*/
static class IODisposeHandler extends ChannelHandlerAdapter {
WriteThread writeThread;
/**
* 建立連接
*
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("收到連接:" + ctx.channel());
//新起寫數據線程
writeThread = new WriteThread(ctx);
writeThread.start();
}
/**
* 消息讀取
*
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Msg m = (Msg) msg;
System.out.println("server receive msg:" + JSON.toJSONString(m));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("連接出錯");
writeThread.runFlag = false;
ctx.close();
}
}
/**
* 寫數據線程
*/
static class WriteThread extends Thread {
ChannelHandlerContext ctx;
//線程關閉標誌位
volatile boolean runFlag = true;
public WriteThread(ChannelHandlerContext ctx) {
this.ctx = ctx;
}
@Override
public void run() {
try {
Scanner scanner = new Scanner(System.in);
while (runFlag) {
System.out.print("server send msg:");
String msg = scanner.nextLine();
Msg m = new Msg("one", msg);
//發送數據
ctx.channel().writeAndFlush(m);
}
} catch (Exception e) {
}
}
}
}