步骤1:创建请求和响应对应的proto模型数据结构
(1)request.proto
内容如下:
syntax = "proto3";
option java_package = "com.bfxy.netty.protobuf";
option java_outer_classname = "RequestModule";
message Request {
string id = 1;
int32 sequence = 2;
string data = 3;
}
(2)response.proto
内容如下:
syntax = "proto3";
option java_package = "com.bfxy.netty.protobuf";
option java_outer_classname = "ResponseModule";
message Response {
string id = 1;
int32 code = 2;
string desc = 3;
}
步骤2:模型数据结构,生成对应java类模型实体
(1)创建request.bat 和 reponse.bat文件
request.bat内容:
protoc ./proto/request.proto --java_out=./src/main/java
pause
reponse.bat内容:
protoc ./proto/response.proto --java_out=./src/main/java
pause
(2)生成对应java类模型实体,RequestModule.java,ResponseModule.java
步骤3:创建client
(1)创建netty对应client类
import com.bfxy.netty.protobuf.ResponseModule;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
public class Client {
public void connect(int port, String host) throws Exception {
// 配置客户端NIO线程组
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
ch.pipeline().addLast(new ProtobufDecoder(ResponseModule.Response.getDefaultInstance()));
ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
ch.pipeline().addLast(new ProtobufEncoder());
ch.pipeline().addLast(new ClientHandler());
}
});
// 发起异步连接操作
ChannelFuture f = b.connect(host, port).sync();
System.out.println("Client Start .. ");
// 当代客户端链路关闭
f.channel().closeFuture().sync();
} finally {
// 优雅退出,释放NIO线程组
group.shutdownGracefully();
}
}
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
int port = 8080;
if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException e) {
// 采用默认值
}
}
new Client().connect(port, "127.0.0.1");
}
}
(2)创建netty,client类对应逻辑处理类
import com.bfxy.netty.protobuf.RequestModule;
import com.bfxy.netty.protobuf.RequestModule.Request;
import com.bfxy.netty.protobuf.ResponseModule;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
public class ClientHandler extends ChannelInboundHandlerAdapter {
/**
* Creates a client-side handler.
*/
public ClientHandler() {
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
System.err.println("客户端通道激活");
for(int i =0; i< 100; i ++) {
ctx.writeAndFlush(createRequest(i));
}
}
private Request createRequest(int i) {
return RequestModule.Request.newBuilder().setId("主键" + i)
.setSequence(i)
.setData("数据内容" + i)
.build();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
ResponseModule.Response response = (ResponseModule.Response)msg;
System.err.println("客户端:" + response.getId() + "," + response.getCode() + "," + response.getDesc());
} finally {
ReferenceCountUtil.release(msg);
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
步骤3:创建clien
(1)创建netty对应server类
import com.bfxy.netty.protobuf.RequestModule;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
public class Server {
public void bind(int port) throws Exception {
// 配置服务端的NIO线程组
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
ch.pipeline().addLast(new ProtobufDecoder(RequestModule.Request.getDefaultInstance()));
ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
ch.pipeline().addLast(new ProtobufEncoder());
ch.pipeline().addLast(new ServerHandler());
}
});
// 绑定端口,同步等待成功
ChannelFuture f = b.bind(port).sync();
System.out.println("Server Start .. ");
// 等待服务端监听端口关闭
f.channel().closeFuture().sync();
} finally {
// 优雅退出,释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port = 8080;
if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException e) {
// 采用默认值
}
}
new Server().bind(port);
}
}
(2)创建netty,server类对应逻辑处理类
import com.bfxy.netty.protobuf.RequestModule;
import com.bfxy.netty.protobuf.ResponseModule;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class ServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
RequestModule.Request request = (RequestModule.Request)msg;
System.err.println("服务端:" + request.getId() + "," + request.getSequence() + "," + request.getData());
ctx.writeAndFlush(createResponse(request.getId(), request.getSequence()));
}
private ResponseModule.Response createResponse(String id, int seq) {
return ResponseModule.Response.newBuilder()
.setId(id)
.setCode(seq)
.setDesc("响应报文")
.build();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
Protobuf序列化和反序列化工具
import java.util.Arrays;
import com.google.protobuf.InvalidProtocolBufferException;
public class TestProtobuf {
/**
* serialObject2Bytes 序列化
* @return
*/
public static byte[] serialObject2Bytes() {
UserModule.User.Builder userBuilder = UserModule.User.newBuilder();
userBuilder
.setUserId("1001")
.setAge(30)
.setUserName("张三")
.addFavorite("足球")
.addFavorite("撸码");
UserModule.User user = userBuilder.build();
/**
* 序列化机制:
* 1. java序列化 比如一个int类型(4个字节长度)
* // int a = 2 & int a = 110000000
* java的序列化无论真是的int类型数值大小实际占用多少个字节,在内存中都是以4个长度(32位)
* protobuf序列化机制:
* 是按照实际的数据大小去动态伸缩的, 因此很多时候我们的int数据并没有实际占用到4个字节
* 所以protobuf序列化后一般都会比int类型(java序列化机制)的占用长度要小很多!
*/
byte[] data = user.toByteArray();
System.err.println(Arrays.toString(data));
return data;
}
/**
* $serialBytes2Object 反序列化
* @param data
* @return
*/
public static UserModule.User serialBytes2Object(byte[] data) {
try {
return UserModule.User.parseFrom(data);
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
byte[] data = serialObject2Bytes();
UserModule.User user = serialBytes2Object(data);
System.err.println("userId: " + user.getUserId());
System.err.println("age: " + user.getAge());
System.err.println("userName: " + user.getUserName());
System.err.println("favorite: " + user.getFavoriteList());
}
}