基于protobuf的netty客户端实现

基本配置和上文一样,不在赘述了,直接贴代码

基于protobuf的netty客户端实现_第1张图片

1.nettClient

/**
 * @author Simon Hua
 * @date 2020/2/11 9:45
 */
@Component
public class NettyClient {

    @Value("${netty.server.host}")
    private String netty_server_host;
    @Value("${netty.server.port}")
    private int netty_server_port;
    @Autowired
    private CustomChannelInitializer customChannelInitializer;

    private static Logger logger = LoggerFactory.getLogger(NettyClient.class);

    /// 通过nio方式来接收连接和处理连接
    private EventLoopGroup group = new NioEventLoopGroup();
    private static Bootstrap bootstrap = new Bootstrap();
    public static Channel channel;

    /**
     * Netty创建全部都是实现自AbstractBootstrap。
     * 客户端的是Bootstrap,服务端的则是    ServerBootstrap。
     * @throws InterruptedException
     * @throws IOException
     **/

    @PostConstruct
    public void initChannel() {
        try {
            bootstrap.group(group);
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.handler(customChannelInitializer);
            bootstrap.remoteAddress(netty_server_host,netty_server_port);
            // 连接服务端
            ChannelFuture f = bootstrap.connect();
            f.addListener(new ConnectionListener());
            channel = f.channel();
//			channel = bootstrap.connect().sync().channel();
        } catch (NumberFormatException e) {
            JSONObject json=new JSONObject();
            json.put("code",-1);
            json.put("msg","启动netty客户端异常,请检查netty监听端口是否正确!");
            logger.error(json.toJSONString(),e);
        }
    }

    /**
     * 重连
     */
    public static void doConnect() {
        ChannelFuture f = null;
        try {
            if (bootstrap != null) {
                f = bootstrap.connect().addListener(new ConnectionListener());
                channel = f.channel();
            }
        } catch (Exception e) {
            JSONObject json=new JSONObject();
            json.put("code",-1);
            json.put("msg","客户端连接失败!");
            logger.error(json.toJSONString(),e);
        }

    }
}

 2.CustomChannelInitializer 

/**
 * @author Simon Hua
 * @date 2020/2/11 9:48
 *
 * 自定义ChannelInitializer,用于初始化ChannelPipeline
 */

@Component
public class CustomChannelInitializer extends ChannelInitializer {

    @Resource
    private NettyClientHandler nettyClientHandler;

    @Override
    protected void initChannel(SocketChannel channel) throws Exception {
        ChannelPipeline channelPipeline = channel.pipeline();

//        channelPipeline.addLast("framer", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2, 0, 2));
//        channelPipeline.addLast("prepender", new LengthFieldPrepender(4, false));

        //心跳发送时间间隔
        channelPipeline.addLast(new IdleStateHandler(0, 60, 0, TimeUnit.SECONDS));

        // 解码和编码,应和客户端一致
        //传输协议 Protobuf
        channelPipeline.addLast(new ProtobufVarint32FrameDecoder());
        channelPipeline.addLast(new ProtobufDecoder(NettyMessage.Content.getDefaultInstance()));
        channelPipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
        channelPipeline.addLast(new ProtobufEncoder());

        //客户端的逻辑
        channelPipeline.addLast("handler",nettyClientHandler);

    }
}

 3.handler

/**
 * @author Simon Hua
 * @date 2020/2/11 9:52
 *
 * netty消息处理
 */
@Component
@ChannelHandler.Sharable

public class NettyClientHandler extends ChannelInboundHandlerAdapter {
    
    private static Logger logger = LoggerFactory.getLogger(NettyClientHandler.class);
    
    /**
     * 建立连接时
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        logger.info("客户端与服务器建立连接,当前时间:{}", Instant.now().toString());
        ctx.fireChannelActive();
    }

    /**
     * 关闭连接时
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.error("客户端失去服务端连接,时间:{}",Instant.now().toString());
        //使用过程中断线重连
        final EventLoop eventLoop = ctx.channel().eventLoop();
        eventLoop.schedule(new Runnable() {
            @Override
            public void run() {
                logger.info("客户端尝试重新连接服务器");
                NettyClient.doConnect();
            }
        }, 1L, TimeUnit.SECONDS);
        super.channelInactive(ctx);
    }

    /**
     * 心跳请求处理
     * 每60秒发送一次心跳请求;
     *
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception {
        logger.info("\nsend heartbeat to server");
        if (obj instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) obj;
            if (IdleState.WRITER_IDLE.equals(event.state())) {  //写通道处于空闲状态,就发送心跳命令
                NettyMessage.Content heartBeat = NettyMessage.Content.newBuilder().
                        setOperateType(NettyConstant.HEART_BEAT).
                        build();
                ctx.writeAndFlush(heartBeat);
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("客户端异常,异常信息:{}", cause.getMessage());
        cause.printStackTrace();
        ctx.close();
    }

    //业务逻辑处理
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //非protobuf格式数据
        if (!(msg instanceof NettyMessage.Content)) {
            logger.error("invalid message");
            return;
        }
        try {
            NettyMessage.Content message = (NettyMessage.Content) msg;
            String operateType = message.getOperateType();
            NettyMessage.Content.Builder responseBuilder = NettyMessage.Content.newBuilder();
        }catch (Exception e) {
            JSONObject json=new JSONObject();
            json.put("code",-1);
            logger.error(json.toJSONString(),e);
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }
    
}

4.listener 

/**
 * @author Simon Hua
 * @date 2020/2/11 9:47
 */
public class ConnectionListener implements ChannelFutureListener {

    private static Logger logger = LoggerFactory.getLogger(ConnectionListener.class);

    @Override
    public void operationComplete(ChannelFuture channelFuture) throws Exception {
        if (!channelFuture.isSuccess()) {
            final EventLoop loop = channelFuture.channel().eventLoop();
            loop.schedule(()->{
                logger.error("客户端连接服务器失败,开始重连操作...");
                NettyClient.doConnect();
            }, 5L, TimeUnit.SECONDS);
            JSONObject json=new JSONObject();
            json.put("code",-1);
            json.put("msg","客户端连接服务器失败,开始重连操作...");
            logger.error(json.toJSONString());
        } else {
            JSONObject json=new JSONObject();
            json.put("code",0);
            json.put("msg","客户端连接服务器成功!");
            logger.error(json.toJSONString());
        }
    }

}

 

你可能感兴趣的:(基于protobuf的netty客户端实现)