在集群环境下服务器之间是要定时进行心跳检测的,那么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 + '\'' +
'}';
}
}