netty-netty使用ProtoBuf

netty-netty使用ProtoBuf

摘自<netty权威指南>

案例

服务器端

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(new ProtobufVarint32FrameDecoder());
                    ch.pipeline().addLast(
                            new ProtobufDecoder(SubscribeReqProto.SubscribeReq.getDefaultInstance()));
                    ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
                    ch.pipeline().addLast(new ProtobufEncoder());
                    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 {
		SubscribeReqProto.SubscribeReq req = (SubscribeReqProto.SubscribeReq) msg;
		if ("netty".equalsIgnoreCase(req.getUserName())) {
			System.out.println("server recv req[x] : [" + req.toString() + "]");
			ctx.writeAndFlush(resp(req.getSubReqID()));
		}
	}

	private SubscribeRespProto.SubscribeResp resp(int subReqID) {
		SubscribeRespProto.SubscribeResp.Builder builder =
				SubscribeRespProto.SubscribeResp.newBuilder();
		builder.setSubReqID(subReqID);
		builder.setDesc("netty book subscribe success...");
		builder.setRespCode(0);
		return builder.build();
	}


	@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(new ProtobufVarint32FrameDecoder());
                    ch.pipeline().addLast(new ProtobufDecoder(
                            SubscribeRespProto.SubscribeResp.getDefaultInstance()
                    ));
                    ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
                    ch.pipeline().addLast(new ProtobufEncoder());
                    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 SubscribeReqProto.SubscribeReq subReq(int i) {
		SubscribeReqProto.SubscribeReq.Builder builder =
				SubscribeReqProto.SubscribeReq.newBuilder();
		builder.setSubReqID(i);
		builder.setProductName("netty definitive book");
		builder.setUserName("netty");
		List<String> address = new ArrayList<>();
		address.add("ShangHai");
		address.add("BeiJing");
		builder.addAllAddress(address);
		return builder.build();
	}

	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) 
                                                throws Exception {
		ctx.flush();
	}
}

注意事项

ProtoBufDecoder仅仅负责解码,并不能解决半包问题,处理半包方案:

  • 使用netty提供的ProtobufVarint32FrameDecoder
  • 继承netty提供的通过半包解码器 LengthFieldBasedFrameDecoder
  • 继承ByteToMessageDecoder,自定义实现

运行结果

# server
server start success...
server recv req[x] : [userName: "netty"
productName: "netty definitive book"
address: "ShangHai"
address: "BeiJing"
]

...

# client

client recv [x]: [desc: "netty book subscribe success..." ]
client recv [x]: [subReqID: 1 desc: "netty book subscribe success..." ]
...
发布了76 篇原创文章 · 获赞 66 · 访问量 51万+

猜你喜欢

转载自blog.csdn.net/u013887008/article/details/104181641