Protobuf跟netty整合

步骤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());
	}
}

你可能感兴趣的:(Java技术栈综合,Protobuf,netty整合)