Netty4.x整合Protobuf编解码框架(二)

目录

    • 回顾
    • 废话不说直接上代码
      • 整体项目工程
      • 服务端开发
      • 客户端开发
    • 打印结果
    • 到此,Netty4.x整合Protobuf编解码框架已全部归整完成。下篇博文我们就用Netty4.x实现一个聊天功能 大家加油!

回顾

上一篇我们对Protobuf有个一个初步的了解,并成功搭建起了开发环境,且对Protobuf API有了一个简单的调试。
在掌握了以上内容后,下面我们使用Netty的Protobuf编解码框架来进行客户端和服务端的开发,通过一个图书订阅的小案例就行讲解说明,那我们就开始吧!

废话不说直接上代码

整体项目工程

代码全部都完整给出,强烈建议自己一遍遍的手动来写,多理解。
理解的越多,则需要记忆的内容就越少
Netty4.x整合Protobuf编解码框架(二)_第1张图片

服务端开发

SubBookServer.java

package com.moreday.netty_protobuf.codec.serializable.netty;

import com.moreday.netty_protobuf.codec.protobuf.BookReqProto;

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;

/**
 * @ClassName SubBookServer
 * @Description TODO(这里用一句话描述这个类的作用)
 * @author 寻找手艺人
 * @Date 2020年4月15日 上午10:46:37
 * @version 1.0.0
 */
public class SubBookServer {
	/**
	 * @Description (TODO这里用一句话描述这个方法的作用)
	 * @param port
	 * @throws Exception
	 */
	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, 1024)
					.handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {

						@Override
						protected void initChannel(SocketChannel ch) throws Exception {
							//ProtobufVarint32FrameDecoder主要用于半包的处理
							ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
							//指定ProtobufDecoder解码器需要的解码后的目标实例类型
							//参数:MessageLite 就是我们的BookReq类型
							ch.pipeline().addLast(new ProtobufDecoder(new BookReqProto.BookReq().getDefaultInstance()));
							ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
							ch.pipeline().addLast(new ProtobufEncoder());
							ch.pipeline().addLast(new SubBookServerHandler());
						}
					});
			ChannelFuture f = b.bind(port).sync();
			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) {
			port = Integer.valueOf(args[0]);
		}
		new SubBookServer().bind(port);
	}
}

SubBookServerHandler.java

package com.moreday.netty_protobuf.codec.serializable.netty;

import com.moreday.netty_protobuf.codec.protobuf.BookReqProto;
import com.moreday.netty_protobuf.codec.protobuf.BookRespProto;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

/**
 * @ClassName SubBookServerHandler
 * @Description TODO(这里用一句话描述这个类的作用)
 * @author 寻找手艺人
 * @Date 2020年4月15日 上午10:50:53
 * @version 1.0.0
 */
public class SubBookServerHandler extends ChannelInboundHandlerAdapter{
	
	/* (非 Javadoc)
	 * Description:
	 * @see io.netty.channel.ChannelInboundHandlerAdapter#channelRead(io.netty.channel.ChannelHandlerContext, java.lang.Object)
	 */
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
	    BookReqProto.BookReq req = (BookReqProto.BookReq) msg;
	    
	    if("寻找手艺人".equalsIgnoreCase(req.getUserName())) {
	    	System.out.println("Server accept client subscribe req ["+req.toString()+"]");
	    	ctx.writeAndFlush(subResp(req.getId()));
	    }
	    
	}

	/**
	 * @Description (TODO这里用一句话描述这个方法的作用)
	 * @param id
	 * @return
	 */
	private BookRespProto.BookResp subResp(int id) {
		BookRespProto.BookResp.Builder builder = BookRespProto.BookResp.newBuilder();
		builder.setSubReqID(id);
		builder.setRespCode(200);
		builder.setDesc("Head First设计模式 book order successed,1 day later,send to the designated address! good lucky~");
		return builder.build();
	}
	
	
}

客户端开发

SubBookClient.java

package com.moreday.netty_protobuf.codec.serializable.netty;

import com.moreday.netty_protobuf.codec.protobuf.BookRespProto;

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;

/**
 * @ClassName SubBookClient
 * @Description TODO(这里用一句话描述这个类的作用)
 * @author 寻找手艺人
 * @Date 2020年4月15日 上午10:48:19
 * @version 1.0.0
 */
public class SubBookClient {
	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
						protected void initChannel(SocketChannel ch) throws Exception {
							// TODO Auto-generated method stub
							ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
							ch.pipeline().addLast(new ProtobufDecoder(BookRespProto.BookResp.getDefaultInstance()));
							ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
							ch.pipeline().addLast(new ProtobufEncoder());
							ch.pipeline().addLast(new SubBookClientHandler());
						}
					});
			ChannelFuture f = b.connect(host, port).sync();
			f.channel().closeFuture().sync();
		} finally {
			group.shutdownGracefully();
		}

	}

	public static void main(String[] args) throws Exception {
		int port = 8080;
		if(args!=null && args.length>0) {
			port = Integer.valueOf(args[0]);
		}
		new SubBookClient().connect(port, "127.0.0.1");
	}
}

SubBookClientHandler.java

package com.moreday.netty_protobuf.codec.serializable.netty;

import java.util.ArrayList;
import java.util.List;

import com.moreday.netty_protobuf.codec.protobuf.BookReqProto;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

/**
 * @ClassName SubBookClientHandler
 * @Description TODO(这里用一句话描述这个类的作用)
 * @author 寻找手艺人
 * @Date 2020年4月15日 下午12:46:06
 * @version 1.0.0
 */
public class SubBookClientHandler extends ChannelInboundHandlerAdapter {

	 /* (非 Javadoc)
	 * Description:
	 * @see io.netty.channel.ChannelInboundHandlerAdapter#channelActive(io.netty.channel.ChannelHandlerContext)
	 */
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		for(int i=1;i<=3;i++) {
			ctx.writeAndFlush(subBookReq(i));
		}
	}

	/**
	 * @Description (TODO这里用一句话描述这个方法的作用)
	 * @param i
	 * @return
	 */
	private BookReqProto.BookReq subBookReq(int i) {

        BookReqProto.BookReq.Builder builder = BookReqProto.BookReq.newBuilder();
        builder.setId(i);
        builder.setProductName("Head First设计模式");
        builder.setUserName("寻找手艺人");
        List<String> address = new ArrayList<String>();
		address.add("98.00桐梓");
		address.add("198.00遵义");
		address.add("298.00济宁");
		address.add("398.00青岛");
		builder.addAllAddress(address);
		return builder.build();
	}
	
	/* (非 Javadoc)
	 * Description:
	 * @see io.netty.channel.ChannelInboundHandlerAdapter#channelRead(io.netty.channel.ChannelHandlerContext, java.lang.Object)
	 */
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		// TODO Auto-generated method stub
		System.out.println("Client Receive Server response :["+msg+"]");
	}
}

打印结果

客户端发起3次订阅请求,服务端呈现3次请求响应,完全符合我们的设计初衷。
Netty4.x整合Protobuf编解码框架(二)_第2张图片

到此,Netty4.x整合Protobuf编解码框架已全部归整完成。下篇博文我们就用Netty4.x实现一个聊天功能 大家加油!

你可能感兴趣的:(Netty)