《netty权威指南》之模拟服务器之间的心跳检测

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lyzx_in_csdn/article/details/83143646
在集群环境下服务器之间是要定时进行心跳检测的,那么netty可以用来做这件事,
在集群环境中,选定一台服务区做master,其余的做salve
即master <==>  server端
   salve   <==>  客户端
客户端定时像服务端发送请求,当然在请求之间先进行认证

服务端代码如下

package com.lyzx.netty.netty06;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.ReadTimeoutHandler;

/**
 * @author hero.li
 * 
 */
public class Server{

    public static void main(String[] args) throws InterruptedException {
        //开启两个线程组,一个用于接受客户端的请求   另一个用于异步的网络IO的读写
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        //Netty启动的辅助类 里面封装了客户端和服务端的链接以及如何处理选择器 selector等逻辑
        ServerBootstrap b = new ServerBootstrap();

        //传入两个线程组,设置传输块大小为1k,
//添加ServerHandler类型的过滤器(表示如何处理这些消息,过滤器当然要集成netty的一个接口)
        b.group(bossGroup,workerGroup)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG,1024)
                .childOption(ChannelOption.SO_KEEPALIVE,Boolean.TRUE)
                .childHandler(new ChannelInitializer<SocketChannel>(){
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception{
                        ChannelHandler[] arr = {MarshallingCodeCFactory.marshallingDecoder(),
                                                MarshallingCodeCFactory.marshallingEncoder(),
                                                new ReadTimeoutHandler(30),
                                                new ServerHandler()};
                        ch.pipeline().addLast(arr);
                    }
                });

        //同步等待绑定端口结束
        ChannelFuture f = b.bind(9988).sync();
        //等待服务端监听端口关闭
        f.channel().closeFuture().sync();
        //优雅的关闭线程组
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }
}

服务端Handler

package com.lyzx.netty.netty06;

import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * 对于网事件做读写,通常只要关注channelRead()和exceptionCaught()即可
 */
public class ServerHandler extends ChannelInboundHandlerAdapter {
    private static final String AUTH_SUCCESS_FLAG = "AUTH_SUCCESS";
    private static final String AUTH_FAIL_FLAG = "AUTH_FAIL";

    private static final Map<String,String> KEYS = new ConcurrentHashMap<>();
    static{
        //这儿本应该读取数据库以初始化可以访问该服务器的客户端
        KEYS.put("192.168.22.170","abcd007");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if(msg.getClass() == String.class){
            //刚建立连接时的握手信息
            String ipAndSuffix = String.valueOf(msg);
            String[] ipAndSuffiArr = ipAndSuffix.split("_");
            String ip = ipAndSuffiArr[0];
            String suffix  = ipAndSuffiArr[1];
            System.out.println("ip:"+ip+"   ,  "+suffix);
            if(KEYS.containsKey(ip)){
                if(suffix.equals(KEYS.get(ip))){
                    ctx.channel().writeAndFlush(AUTH_SUCCESS_FLAG);
                    return;
                }
            }
            ctx.channel()
               .writeAndFlush(AUTH_FAIL_FLAG)
               .addListener(ChannelFutureListener.CLOSE);
        }else{
            System.out.println("server:channelRead____通道可读开始");
            NettyRequest nr = (NettyRequest)msg;
            System.out.println("server:收到的消息____:"+nr);

            String datetime = LocalDateTime.now()
                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS"));
            nr.setMsg(datetime);
            ctx.channel().writeAndFlush(nr);
            System.out.println("server:channelRead____通道可读结束");
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("server:channelReadComplete____通道可读完成 ");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("server:exceptionCaught____发生异常");
        ctx.close();
    }

}

客户端代码

package com.lyzx.netty.netty06;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.ReadTimeoutHandler;


public class Client {

    public static void main(String[] args) throws InterruptedException {
        NioEventLoopGroup group = new NioEventLoopGroup();
        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{
                            ChannelHandler[] arr = 
            
                {MarshallingCodeCFactory.marshallingDecoder(),                             
                 MarshallingCodeCFactory.marshallingEncoder(),
                 new ReadTimeoutHandler(30),
                 new ClientHandler()};
                            ch.pipeline().addLast(arr);
                    }
                });
        ChannelFuture f = b.connect("127.0.0.1", 9988).sync();

        f.channel().closeFuture().sync();
        group.shutdownGracefully();
    }
}

客户端Handler

package com.lyzx.netty.netty06;

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

import java.net.InetAddress;

public class ClientHandler extends ChannelInboundHandlerAdapter {
    private static final String AUTH_SUCCESS_FLAG = "AUTH_SUCCESS";
    private static final String AUTH_FAIL_FLAG = "AUTH_FAIL";
    private String auth_suffix = "abcd007";

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client:channelActive____通道激活开始");
        String ip = InetAddress.getLocalHost().getHostAddress();
        String auth_key = ip+"_"+auth_suffix;
        ctx.channel().writeAndFlush(auth_key);
        System.out.println("client:channelActive____通道激活结束");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx,Object msg) throws Exception {
        if(msg.getClass() == String.class){
            if(AUTH_SUCCESS_FLAG.equals(msg)){
                new Thread(new Scheduler(ctx)).start();
            }else{
                System.out.println("========认证失败:"+AUTH_FAIL_FLAG);
            }
        }else{
            NettyRequest nr = (NettyRequest)msg;
            System.out.println("client____response time:"+nr);
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client:通道可读完成");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("client:发生异常");

    }
}

class Scheduler implements Runnable{
    private  ChannelHandlerContext ctx;

    public Scheduler(ChannelHandlerContext ctx){
        this.ctx = ctx;
    }

    @Override
    public void run() {
//模拟定时发送心跳消息
        for(int i=0;i<20;i++){
            NettyRequest nr = new NettyRequest();
            nr.setId((long)i);
            nr.setCode(i);
            nr.setMsg("data_data:"+i);
            ctx.channel().writeAndFlush(nr);
            try {Thread.sleep(2000);
            }catch(InterruptedException e){e.printStackTrace();}
        }
    }
}

其他工具类

package com.lyzx.netty.netty06;

import io.netty.handler.codec.marshalling.*;
import org.jboss.marshalling.MarshallerFactory;
import org.jboss.marshalling.Marshalling;
import org.jboss.marshalling.MarshallingConfiguration;

/**
 * Marshalling工厂
 * @author(alienware)
 * @since 2014-12-16
 */
public final class MarshallingCodeCFactory {

    /**
     * 创建Jboss Marshalling解码器MarshallingDecoder
     * @return MarshallingDecoder
     */
    public static MarshallingDecoder marshallingDecoder() {
    	//首先通过Marshalling工具类的方法获取Marshalling实例对象 
        //参数serial标识创建的是java序列化工厂对象。
		final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
		//创建了MarshallingConfiguration对象,配置了版本号为5 
		final MarshallingConfiguration configuration = new MarshallingConfiguration();
		configuration.setVersion(5);
		//根据marshallerFactory和configuration创建provider
		UnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, configuration);
		//构建Netty的MarshallingDecoder对象,
        //俩个参数分别为provider和单个消息序列化后的最大长度
		MarshallingDecoder decoder = new MarshallingDecoder(provider, 1024 * 1024 * 1);
		return decoder;
    }

    /**
     * 创建Jboss Marshalling编码器MarshallingEncoder
     * @return MarshallingEncoder
     */
    public static MarshallingEncoder marshallingEncoder() {
		final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
		final MarshallingConfiguration configuration = new MarshallingConfiguration();
		configuration.setVersion(5);
		MarshallerProvider provider = new DefaultMarshallerProvider(marshallerFactory, configuration);
		//构建Netty的MarshallingEncoder对象,
        //MarshallingEncoder用于实现序列化接口的POJO对象序列化为二进制数组
		MarshallingEncoder encoder = new MarshallingEncoder(provider);
		return encoder;
    }
}

通信实体类

package com.lyzx.netty.netty06;

import java.io.Serializable;

public class NettyRequest implements Serializable {
    private Long id;

    private int code;
    private String msg;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "NettyRequest{" +
                "id=" + id +
                ", code=" + code +
                ", msg='" + msg + '\'' +
                '}';
    }

}

完整版代码:https://github.com/lyzxhero/Netty

猜你喜欢

转载自blog.csdn.net/lyzx_in_csdn/article/details/83143646
今日推荐