netty4 java序列化_Netty(四、序列化与反序列化)

序列化就是将对象的状态信息转换成可以存储或传输的过程。

Netty序列化对象一般有以下几种方式:

JDK

JBoss Marshalling

Protocol Buffers

kryo

JDK

实体类

Request

packagecom.wk.test.nettyTest.jdk;importjava.io.Serializable;public class Request implementsSerializable {privateString id;privateString name;privateString info;publicString getId() {returnid;

}public voidsetId(String id) {this.id =id;

}publicString getName() {returnname;

}public voidsetName(String name) {this.name =name;

}publicString getInfo() {returninfo;

}public voidsetInfo(String info) {this.info =info;

}

}

Response

packagecom.wk.test.nettyTest.jdk;importjava.io.Serializable;public class Response implementsSerializable{private static final long serialVersionUID = 1L;privateString id;privateString name;privateString responseMessage;publicString getId() {returnid;

}public voidsetId(String id) {this.id =id;

}publicString getName() {returnname;

}public voidsetName(String name) {this.name =name;

}publicString getResponseMessage() {returnresponseMessage;

}public voidsetResponseMessage(String responseMessage) {this.responseMessage =responseMessage;

}

}

服务端

NettyServerTest

packagecom.wk.test.nettyTest.jdk;importio.netty.bootstrap.ServerBootstrap;importio.netty.channel.ChannelFuture;importio.netty.channel.ChannelInitializer;importio.netty.channel.ChannelOption;importio.netty.channel.EventLoopGroup;importio.netty.channel.nio.NioEventLoopGroup;importio.netty.channel.socket.SocketChannel;importio.netty.channel.socket.nio.NioServerSocketChannel;importio.netty.handler.codec.serialization.ClassResolvers;importio.netty.handler.codec.serialization.ObjectDecoder;importio.netty.handler.codec.serialization.ObjectEncoder;importio.netty.handler.logging.LogLevel;importio.netty.handler.logging.LoggingHandler;importio.netty.handler.timeout.ReadTimeoutHandler;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;public classNettyServerTest {private static final Logger logger = LoggerFactory.getLogger(NettyServerTest.class);public static void main(String[] args) throwsInterruptedException {

EventLoopGroup pGroup= newNioEventLoopGroup();

EventLoopGroup cGroup= newNioEventLoopGroup();

ServerBootstrap b= newServerBootstrap();

b.group(pGroup, cGroup)

.channel(NioServerSocketChannel.class)

.option(ChannelOption.SO_BACKLOG,1024)//设置日志

.handler(newLoggingHandler(LogLevel.INFO))

.childHandler(new ChannelInitializer() {protected void initChannel(SocketChannel sc) throwsException {

sc.pipeline().addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));

sc.pipeline().addLast(newObjectEncoder());

sc.pipeline().addLast(new ReadTimeoutHandler(5));

sc.pipeline().addLast(newServerHandler());

}

});

ChannelFuture cf= b.bind(8090).sync();

cf.channel().closeFuture().sync();

pGroup.shutdownGracefully();

cGroup.shutdownGracefully();

}

}

ServerHandler

packagecom.wk.test.nettyTest.jdk;importio.netty.channel.ChannelHandlerContext;importio.netty.channel.ChannelInboundHandlerAdapter;public class ServerHandler extendsChannelInboundHandlerAdapter {

@Overridepublic void channelActive(ChannelHandlerContext ctx) throwsException {

}

@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throwsException {

Request request=(Request)msg;

System.out.println("Server : " + request.getId() + ", " + request.getName() + ", " +request.getInfo());

Response response= newResponse();

response.setId(request.getId());

response.setName("response" +request.getName());

response.setResponseMessage("响应内容" +request.getInfo());

ctx.writeAndFlush(response);

}

@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throwsException {

}

@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throwsException {

ctx.close();

}

}

客户端

NettyClientTest

packagecom.wk.test.nettyTest.jdk;importio.netty.bootstrap.Bootstrap;importio.netty.channel.ChannelFuture;importio.netty.channel.ChannelInitializer;importio.netty.channel.EventLoopGroup;importio.netty.channel.nio.NioEventLoopGroup;importio.netty.channel.socket.SocketChannel;importio.netty.channel.socket.nio.NioSocketChannel;importio.netty.handler.codec.serialization.ClassResolvers;importio.netty.handler.codec.serialization.ObjectDecoder;importio.netty.handler.codec.serialization.ObjectEncoder;importio.netty.handler.logging.LogLevel;importio.netty.handler.logging.LoggingHandler;importio.netty.handler.timeout.ReadTimeoutHandler;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;public classNettyClientTest {private static final Logger logger = LoggerFactory.getLogger(NettyClientTest.class);private static classSingletonHolder {static final NettyClientTest instance = newNettyClientTest();

}public staticNettyClientTest getInstance() {returnSingletonHolder.instance;

}privateEventLoopGroup group;privateBootstrap b;privateChannelFuture cf;privateNettyClientTest() {

group= newNioEventLoopGroup();

b= newBootstrap();

b.group(group)

.channel(NioSocketChannel.class)

.handler(newLoggingHandler(LogLevel.INFO))

.handler(new ChannelInitializer() {

@Overrideprotected void initChannel(SocketChannel sc) throwsException {

sc.pipeline().addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));

sc.pipeline().addLast(newObjectEncoder());//超时handler(当服务器端与客户端在指定时间以上没有任何进行通信,则会关闭响应的通道,主要为减小服务端资源占用)

sc.pipeline().addLast(new ReadTimeoutHandler(5));

sc.pipeline().addLast(newClientHandler());

}

});

}public voidconnect() {try{this.cf = b.connect("127.0.0.1", 8090).sync();

System.out.println("远程服务器已经连接, 可以进行数据交换..");

}catch(Exception e) {

e.printStackTrace();

}

}publicChannelFuture getChannelFuture() {if (this.cf == null) {this.connect();

}if (!this.cf.channel().isActive()) {this.connect();

}return this.cf;

}public static void main(String[] args) throwsInterruptedException {final NettyClientTest c =NettyClientTest.getInstance();

ChannelFuture future=c.getChannelFuture();

Request request= newRequest();

request.setId("1");

request.setName("上杉绘梨衣");

request.setInfo("04.24,和Sakura去东京天空树,世界上最暖和的地方在天空树的顶上。");

future.channel().writeAndFlush(request).sync();

Request request2= newRequest();

request2.setId("2");

request2.setName("上杉绘梨衣");

request2.setInfo("04.26,和Sakura去明治神宫,有人在那里举办婚礼。");

future.channel().writeAndFlush(request2);

Request request3= newRequest();

request3.setId("3");

request3.setName("上杉绘梨衣");

request3.setInfo("04.25,和Sakura去迪士尼,鬼屋很可怕,但是有Sakura在,所以不可怕。");

future.channel().writeAndFlush(request3);

Request request4= newRequest();

request4.setId("4");

request4.setName("上杉绘梨衣");

request4.setInfo("Sakura最好了。");

future.channel().writeAndFlush(request4);

future.channel().closeFuture().sync();

}

}

ClientHandler

packagecom.wk.test.nettyTest.jdk;importio.netty.channel.ChannelHandlerContext;importio.netty.channel.ChannelInboundHandlerAdapter;importio.netty.util.ReferenceCountUtil;public class ClientHandler extendsChannelInboundHandlerAdapter {

@Overridepublic void channelActive(ChannelHandlerContext ctx) throwsException {

}

@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throwsException {try{

Response resp=(Response)msg;

System.out.println("Client : " + resp.getId() + ", " + resp.getName() + ", " +resp.getResponseMessage());

}finally{

ReferenceCountUtil.release(msg);

}

}

@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throwsException {

}

@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throwsException {

ctx.close();

}

}

JBoss Marshalling

这种序列化效率比JDK快三倍左右,这里暂不介绍。

protobuf

谷歌开源的一种二进制数据格式,是目前序列化最快的。

相较于json和xml来说,序列化后体积小,传输速率快。序列化后不可读,必须反序列化才可读。

使用

1.下载

这里下载protoc-3.11.4-win64,windows系统使用的protoc.exe

2.编写proto格式文件

我们需要编写一个.proto格式的协议文件,通过该协议文件来生产java类,具体的语法和规则可以参考官方文档。这里只举个例子:

Request.proto

syntax = "proto3";

option java_package= "com.wk.test.nettyTest.proto";

option java_outer_classname= "Request";

message MessageRequest{

uint64 id= 1;

string name= 2;

string info= 3;

}

syntax = "proto3";是使用的协议版本是3

java_package 是生成文件的包路径

java_outer_classname 是类名

message MessageRequest{

uint64 id = 1;

string name = 2;

string info = 3;

}

消息体内容:

64 int类型的id

string 姓名和内容

后面的数字代表一个应答序号,同一级别下不可重复

3.生成协议文件对应的消息类

CMD命令到我们下载好的protoc.exe目录下,执行命令

protoc.exe ./Request.proto --java_out=./

生成Requst.java

4.编写代码

准备工作已经结束了,我们将.proto文件和生成的java文件放入相对应的程序中就可以开始开发了

开发

pom.xml

com.google.protobuf

protobuf-java

3.11.4

这里注意要跟下载的protoc.exe版本一致

实体类

就是生成的java和proto文件

服务端

NettyServerTest

packagecom.wk.test.nettyTest.proto;importio.netty.bootstrap.ServerBootstrap;importio.netty.channel.ChannelFuture;importio.netty.channel.ChannelInitializer;importio.netty.channel.ChannelOption;importio.netty.channel.EventLoopGroup;importio.netty.channel.nio.NioEventLoopGroup;importio.netty.channel.socket.SocketChannel;importio.netty.channel.socket.nio.NioServerSocketChannel;importio.netty.handler.codec.protobuf.ProtobufDecoder;importio.netty.handler.codec.protobuf.ProtobufEncoder;importio.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;importio.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;importio.netty.handler.logging.LogLevel;importio.netty.handler.logging.LoggingHandler;importio.netty.handler.timeout.ReadTimeoutHandler;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;public classNettyServerTest {private static final Logger logger = LoggerFactory.getLogger(NettyServerTest.class);public static void main(String[] args) throwsInterruptedException {

EventLoopGroup pGroup= newNioEventLoopGroup();

EventLoopGroup cGroup= newNioEventLoopGroup();

ServerBootstrap b= newServerBootstrap();

b.group(pGroup, cGroup)

.channel(NioServerSocketChannel.class)

.option(ChannelOption.SO_BACKLOG,1024)//设置日志

.handler(newLoggingHandler(LogLevel.INFO))

.childHandler(new ChannelInitializer() {protected void initChannel(SocketChannel sc) throwsException {

sc.pipeline().addLast(newProtobufVarint32FrameDecoder());

sc.pipeline().addLast(newProtobufDecoder(Request.MessageRequest.getDefaultInstance()));

sc.pipeline().addLast(newProtobufVarint32LengthFieldPrepender());

sc.pipeline().addLast(newProtobufEncoder());

sc.pipeline().addLast(new ReadTimeoutHandler(5));

sc.pipeline().addLast(newServerHandler());

}

});

ChannelFuture cf= b.bind(8090).sync();

cf.channel().closeFuture().sync();

pGroup.shutdownGracefully();

cGroup.shutdownGracefully();

}

}

ServerHandler

packagecom.wk.test.nettyTest.proto;importio.netty.channel.ChannelHandlerContext;importio.netty.channel.ChannelInboundHandlerAdapter;public class ServerHandler extendsChannelInboundHandlerAdapter {

@Overridepublic void channelActive(ChannelHandlerContext ctx) throwsException {

}

@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throwsException {

Request.MessageRequest request=(Request.MessageRequest)msg;

System.out.println("Server : " + request.getId() + ", " + request.getName() + ", " +request.getInfo());

ctx.writeAndFlush(request);

}

@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throwsException {

}

@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throwsException {

ctx.close();

}

}

客户端

NettyClientTest

packagecom.wk.test.nettyTest.proto;importio.netty.bootstrap.Bootstrap;importio.netty.channel.ChannelFuture;importio.netty.channel.ChannelInitializer;importio.netty.channel.EventLoopGroup;importio.netty.channel.nio.NioEventLoopGroup;importio.netty.channel.socket.SocketChannel;importio.netty.channel.socket.nio.NioSocketChannel;importio.netty.handler.codec.protobuf.ProtobufDecoder;importio.netty.handler.codec.protobuf.ProtobufEncoder;importio.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;importio.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;importio.netty.handler.logging.LogLevel;importio.netty.handler.logging.LoggingHandler;importio.netty.handler.timeout.ReadTimeoutHandler;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;public classNettyClientTest {private static final Logger logger = LoggerFactory.getLogger(NettyClientTest.class);private static classSingletonHolder {static final NettyClientTest instance = newNettyClientTest();

}public staticNettyClientTest getInstance() {returnSingletonHolder.instance;

}privateEventLoopGroup group;privateBootstrap b;privateChannelFuture cf;privateNettyClientTest() {

group= newNioEventLoopGroup();

b= newBootstrap();

b.group(group)

.channel(NioSocketChannel.class)

.handler(newLoggingHandler(LogLevel.INFO))

.handler(new ChannelInitializer() {

@Overrideprotected void initChannel(SocketChannel sc) throwsException {

sc.pipeline().addLast(newProtobufVarint32FrameDecoder());

sc.pipeline().addLast(newProtobufDecoder(Request.MessageRequest.getDefaultInstance()));

sc.pipeline().addLast(newProtobufVarint32LengthFieldPrepender());

sc.pipeline().addLast(newProtobufEncoder());//超时handler(当服务器端与客户端在指定时间以上没有任何进行通信,则会关闭响应的通道,主要为减小服务端资源占用)

sc.pipeline().addLast(new ReadTimeoutHandler(5));

sc.pipeline().addLast(newClientHandler());

}

});

}public voidconnect() {try{this.cf = b.connect("127.0.0.1", 8090).sync();

System.out.println("远程服务器已经连接, 可以进行数据交换..");

}catch(Exception e) {

e.printStackTrace();

}

}publicChannelFuture getChannelFuture() {if (this.cf == null) {this.connect();

}if (!this.cf.channel().isActive()) {this.connect();

}return this.cf;

}public static void main(String[] args) throwsInterruptedException {final NettyClientTest c =NettyClientTest.getInstance();

ChannelFuture future=c.getChannelFuture();

Request.MessageRequest.Builder builder=Request.MessageRequest.newBuilder();

builder.setId(1);

builder.setName("上杉绘梨衣");

builder.setInfo("04.24,和Sakura去东京天空树,世界上最暖和的地方在天空树的顶上。");

future.channel().writeAndFlush(builder.build()).sync();

Request.MessageRequest.Builder builder2=Request.MessageRequest.newBuilder();

builder2.setId(2);

builder2.setName("上杉绘梨衣");

builder2.setInfo("04.26,和Sakura去明治神宫,有人在那里举办婚礼。");

future.channel().writeAndFlush(builder2.build());

Request.MessageRequest.Builder builder3=Request.MessageRequest.newBuilder();

builder3.setId(3);

builder3.setName("上杉绘梨衣");

builder3.setInfo("04.25,和Sakura去迪士尼,鬼屋很可怕,但是有Sakura在,所以不可怕。");

future.channel().writeAndFlush(builder3.build());

Request.MessageRequest.Builder builder4=Request.MessageRequest.newBuilder();

builder4.setId(4);

builder4.setName("上杉绘梨衣");

builder4.setInfo("Sakura最好了。");

future.channel().writeAndFlush(builder4.build());

future.channel().closeFuture().sync();

}

}

ClientHandler

packagecom.wk.test.nettyTest.proto;importio.netty.channel.ChannelHandlerContext;importio.netty.channel.ChannelInboundHandlerAdapter;importio.netty.util.ReferenceCountUtil;public class ClientHandler extendsChannelInboundHandlerAdapter {

@Overridepublic void channelActive(ChannelHandlerContext ctx) throwsException {

}

@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throwsException {try{

Request.MessageRequest request=(Request.MessageRequest)msg;

System.out.println("Server : " + request.getId() + ", " + request.getName() + ", " +request.getInfo());

}finally{

ReferenceCountUtil.release(msg);

}

}

@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throwsException {

}

@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throwsException {

ctx.close();

}

}

优缺点

优点:protobuf是目前序列化最快的没有之一,较json,xml传输体积小,速率高,适合高性能通讯的应用场景

缺点:如果修改消息内容,则需要重新生成java类。proto文件和java文件不对应则报错。

Kryo(推荐使用)

kryo是基于proto的序列化框架,目前的dubbo中就是使用的它,速率仅次于protobuf,体积小,且不用通过proto文件生成java类。

pom.xml

com.esotericsoftware

kryo

5.0.0-RC5

实体类 Request

packagecom.wk.test.nettyTest.kryo;importjava.io.Serializable;public class Request implementsSerializable {privateString id;privateString name;privateString info;publicString getId() {returnid;

}public voidsetId(String id) {this.id =id;

}publicString getName() {returnname;

}public voidsetName(String name) {this.name =name;

}publicString getInfo() {returninfo;

}public voidsetInfo(String info) {this.info =info;

}

}

封装kryo

因为kryo是线程不安全的,因此我们要对kryo进行一层封装

Serializer

序列化接口类

packagecom.wk.test.nettyTest.kryo;public interfaceSerializer {//序列化接口

byte[] serialize(Object object);//反序列化接口

T deserialize(byte[] bytes);

}

KryoSerializer

序列化实现类,通过ThreadLocal 使每个kryo都有一个线程副本,不会相互影响。

packagecom.wk.test.nettyTest.kryo;importcom.esotericsoftware.kryo.Kryo;importcom.esotericsoftware.kryo.io.Input;importcom.esotericsoftware.kryo.io.Output;importcom.esotericsoftware.kryo.serializers.BeanSerializer;importorg.apache.commons.io.IOUtils;importjava.io.ByteArrayInputStream;importjava.io.ByteArrayOutputStream;public class KryoSerializer implementsSerializer {private final Class>clazz;public KryoSerializer(Class>clazz){this.clazz =clazz;

}final ThreadLocal kryoThreadLocal = new ThreadLocal(){

@OverrideprotectedKryo initialValue(){

Kryo kryo= newKryo();

kryo.register(clazz,newBeanSerializer(kryo,clazz));returnkryo;

}

};privateKryo getKryo(){returnkryoThreadLocal.get();

}

@Overridepublic byte[] serialize(Object object) {

ByteArrayOutputStream byteArrayOutputStream= newByteArrayOutputStream();

Output output= newOutput(byteArrayOutputStream);try{

Kryo kryo=getKryo();

kryo.writeObjectOrNull(output,object,object.getClass());

output.flush();returnbyteArrayOutputStream.toByteArray();

}finally{

IOUtils.closeQuietly(output);

IOUtils.closeQuietly(byteArrayOutputStream);

}

}

@Overridepublic T deserialize(byte[] bytes) {if(bytes ==null){return null;

}

ByteArrayInputStream byteArrayInputStream= newByteArrayInputStream(bytes);

Input input= newInput(byteArrayInputStream);try{

Kryo kryo=getKryo();return(T) kryo.readObjectOrNull(input,clazz);

}finally{

IOUtils.closeQuietly(input);

IOUtils.closeQuietly(byteArrayInputStream);

}

}

}

KryoSerializerFactory

工厂类,通过传入class来获取相对应的序列化工具类

packagecom.wk.test.nettyTest.kryo;public classKryoSerializerFactory {public static Serializer getSerializer(Class>clazz){return newKryoSerializer(clazz);

}

}

编码、解码类(也可以称为序列化、反序列化类)

KryoMsgEncoder

packagecom.wk.test.nettyTest.kryo;importio.netty.buffer.ByteBuf;importio.netty.channel.ChannelHandlerContext;importio.netty.handler.codec.MessageToByteEncoder;public class KryoMsgEncoder extends MessageToByteEncoder{private Serializer serializer = KryoSerializerFactory.getSerializer(Request.class);

@Overrideprotected void encode(ChannelHandlerContext channelHandlerContext, Request request, ByteBuf byteBuf) throwsException {byte[] body =serializer.serialize(request);int headLength =body.length;//相当于消息头

byteBuf.writeInt(headLength);//相当于消息体

byteBuf.writeBytes(body);

}

}

KryoMsgDecoder

packagecom.wk.test.nettyTest.kryo;importio.netty.buffer.ByteBuf;importio.netty.channel.ChannelHandlerContext;importio.netty.handler.codec.ByteToMessageDecoder;importjava.util.List;public class KryoMsgDecoder extendsByteToMessageDecoder {private Serializer serializer = KryoSerializerFactory.getSerializer(Request.class);

@Overrideprotected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list) throwsException {//标记读取的指针的位置

byteBuf.markReaderIndex();//获取消息头,也就是长度

int dataLength =byteBuf.readInt();if(dataLength <=0){//长度不对则当前消息有问题,关闭通道

channelHandlerContext.close();

}//长度小于真实长度则重新加载读取指针

if(byteBuf.readableBytes()

byteBuf.resetReaderIndex();return;

}byte[] body = new byte[dataLength];

byteBuf.readBytes(body);

Request request=serializer.deserialize(body);

list.add(request);

}

}

服务端

NettyKryoServer

packagecom.wk.test.nettyTest.kryo;importio.netty.bootstrap.ServerBootstrap;importio.netty.channel.ChannelFuture;importio.netty.channel.ChannelInitializer;importio.netty.channel.ChannelOption;importio.netty.channel.EventLoopGroup;importio.netty.channel.nio.NioEventLoopGroup;importio.netty.channel.socket.SocketChannel;importio.netty.channel.socket.nio.NioServerSocketChannel;importio.netty.handler.logging.LogLevel;importio.netty.handler.logging.LoggingHandler;importio.netty.handler.timeout.ReadTimeoutHandler;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;public classNettyKryoServer {private static final Logger logger = LoggerFactory.getLogger(NettyKryoServer.class);public static void main(String[] args) throwsInterruptedException {

EventLoopGroup pGroup= newNioEventLoopGroup();

EventLoopGroup cGroup= newNioEventLoopGroup();

ServerBootstrap b= newServerBootstrap();

b.group(pGroup, cGroup)

.channel(NioServerSocketChannel.class)

.option(ChannelOption.SO_BACKLOG,1024)//设置日志

.handler(newLoggingHandler(LogLevel.INFO))

.childHandler(new ChannelInitializer() {protected void initChannel(SocketChannel sc) throwsException {

sc.pipeline().addLast(newKryoMsgDecoder());

sc.pipeline().addLast(newKryoMsgEncoder());

sc.pipeline().addLast(new ReadTimeoutHandler(5));

sc.pipeline().addLast(newKryoServerHandler());

}

});

ChannelFuture cf= b.bind(8090).sync();

cf.channel().closeFuture().sync();

pGroup.shutdownGracefully();

cGroup.shutdownGracefully();

}

}

KryoServerHandler

packagecom.wk.test.nettyTest.kryo;importio.netty.channel.ChannelHandlerContext;importio.netty.channel.ChannelInboundHandlerAdapter;public class KryoServerHandler extendsChannelInboundHandlerAdapter {

@Overridepublic void channelActive(ChannelHandlerContext ctx) throwsException {

}

@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throwsException {

Request request=(Request)msg;

System.out.println("Server : " + request.getId() + ", " + request.getName() + ", " +request.getInfo());

ctx.writeAndFlush(request);

}

@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throwsException {

}

@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throwsException {

ctx.close();

}

}

客户端

NettyKryoClient

packagecom.wk.test.nettyTest.kryo;importio.netty.bootstrap.Bootstrap;importio.netty.channel.ChannelFuture;importio.netty.channel.ChannelInitializer;importio.netty.channel.EventLoopGroup;importio.netty.channel.nio.NioEventLoopGroup;importio.netty.channel.socket.SocketChannel;importio.netty.channel.socket.nio.NioSocketChannel;importio.netty.handler.logging.LogLevel;importio.netty.handler.logging.LoggingHandler;importio.netty.handler.timeout.ReadTimeoutHandler;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;public classNettyKryoClient {private static final Logger logger = LoggerFactory.getLogger(NettyKryoClient.class);private static classSingletonHolder {static final NettyKryoClient instance = newNettyKryoClient();

}public staticNettyKryoClient getInstance() {returnSingletonHolder.instance;

}privateEventLoopGroup group;privateBootstrap b;privateChannelFuture cf;privateNettyKryoClient() {

group= newNioEventLoopGroup();

b= newBootstrap();

b.group(group)

.channel(NioSocketChannel.class)

.handler(newLoggingHandler(LogLevel.INFO))

.handler(new ChannelInitializer() {

@Overrideprotected void initChannel(SocketChannel sc) throwsException {

sc.pipeline().addLast(newKryoMsgDecoder());

sc.pipeline().addLast(newKryoMsgEncoder());//超时handler(当服务器端与客户端在指定时间以上没有任何进行通信,则会关闭响应的通道,主要为减小服务端资源占用)

sc.pipeline().addLast(new ReadTimeoutHandler(5));

sc.pipeline().addLast(newKryoClientHandler());

}

});

}public voidconnect() {try{this.cf = b.connect("127.0.0.1", 8090).sync();

System.out.println("远程服务器已经连接, 可以进行数据交换..");

}catch(Exception e) {

e.printStackTrace();

}

}publicChannelFuture getChannelFuture() {if (this.cf == null) {this.connect();

}if (!this.cf.channel().isActive()) {this.connect();

}return this.cf;

}public static void main(String[] args) throwsInterruptedException {final NettyKryoClient c =NettyKryoClient.getInstance();

ChannelFuture future=c.getChannelFuture();

Request request= newRequest();

request.setId("1");

request.setName("上杉绘梨衣");

request.setInfo("04.24,和Sakura去东京天空树,世界上最暖和的地方在天空树的顶上。");

future.channel().writeAndFlush(request).sync();

Request request2= newRequest();

request2.setId("2");

request2.setName("上杉绘梨衣");

request2.setInfo("04.26,和Sakura去明治神宫,有人在那里举办婚礼。");

future.channel().writeAndFlush(request2);

Request request3= newRequest();

request3.setId("3");

request3.setName("上杉绘梨衣");

request3.setInfo("04.25,和Sakura去迪士尼,鬼屋很可怕,但是有Sakura在,所以不可怕。");

future.channel().writeAndFlush(request3);

Request request4= newRequest();

request4.setId("4");

request4.setName("上杉绘梨衣");

request4.setInfo("Sakura最好了。");

future.channel().writeAndFlush(request4);

future.channel().closeFuture().sync();

}

}

KryoClientHandler

packagecom.wk.test.nettyTest.kryo;importio.netty.channel.ChannelHandlerContext;importio.netty.channel.ChannelInboundHandlerAdapter;importio.netty.util.ReferenceCountUtil;public class KryoClientHandler extendsChannelInboundHandlerAdapter {

@Overridepublic void channelActive(ChannelHandlerContext ctx) throwsException {

}

@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throwsException {try{

Request resp=(Request)msg;

System.out.println("Client : " + resp.getId() + ", " + resp.getName() + ", " +resp.getInfo());

}finally{

ReferenceCountUtil.release(msg);

}

}

@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throwsException {

}

@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throwsException {

ctx.close();

}

}

你可能感兴趣的:(netty4,java序列化)