netty4客户端循环侦测服务端的代码实现

近几日系统需要客户端和服务端通信,JMS倒是挺好用,不过由于想把客户端做成脱离其他系统环境独立运行的插件式jar包,所以没有与spring等结合,就扔掉了jms,采用了轻量级的netty,版本为4.0.30Final。在这个需求中,服务端放在我的系统中,客户端是放入其他系统运行的,由于其他系统的部署运行时间无法确定,所以我做了一个可以循环侦测服务端是否启动,并且在服务端断掉之后可以再次循环侦测的客户端。

       整个通信架构是在我这边的系统中存在一个服务端和一个客户端,该客户端用来取数据整合;其他系统中存在一个客户端,用来接收数据存入数据库。客户端由于是放入其他系统的,所以要尽量减少与其他系统整合的配置,所以要增加一个ServletContextListener的实现类,该listener写入web.xml中,会启动客户端。

客户端代码如下:

客户端启动代码:


package com.chrhc.projects.uiap.support.jeecg.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
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 java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

import com.chrhc.projects.uiap.support.jeecg.common.ConfigUtil;

public class ClientDataSyncClient extends Thread{

public boolean flg = false;
public ChannelFuture f = null; 
public static EventLoopGroup workerGroup = new NioEventLoopGroup();
public static Bootstrap b = new Bootstrap();

public static String hostTemp = "";
public static int portTemp = 0;


public static Timer timer = null;
public static ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
private static final ClientDataSyncClient client = new ClientDataSyncClient();

public static ClientDataSyncClient getInstance(){
return client;
}

@SuppressWarnings("static-access")
public void connect(String host, int port) throws Exception {
//=====================================没有启动bootstrap的版本,可以使用,但无法循环连接服务器=======================================//
// NioEventLoopGroup group = new NioEventLoopGroup(); 
// 
// NioSocketChannel channel = new NioSocketChannel(); //创建一个channel,待会用它来发起链接
// channel.pipeline().addFirst(new ClientDataSyncClientHandler()); //为这个channel添加一个初始化的handler,用于响应待会channel建立成功
// group.register(channel); //注册这个channel
 channel.bind(new InetSocketAddress(ConfigUtil.getString("localServerHost"),ConfigUtil.getInt("localServerPort")));
// while(true){
// try{
// ChannelFuture f = channel.connect(new InetSocketAddress(host, port)); //调用connect方法
// f.addListener(new ChannelFutureListener() {
// public void operationComplete(ChannelFuture future)
// throws Exception {
// if (future.isSuccess()) {
// flag++;
// System.out.println("客户端连接服务器成功:" + future.isDone());
// } else {
// if (future.isCancelled()) {
// System.out.println("客户端连接服务器取消");
// } else {
// System.out.println("客户端连接服务器错误Connect Exception:Success: "
// + future.isSuccess() + " Done: "
// + future.isDone() + " Cause: "
// + future.cause().toString());
// }
// }
// }
// });
// }catch(Exception e){
// System.out.println("连接服务器失败 ");
// e.printStackTrace();
// }
// if(flag>=1){
// break;
// }else{
// Thread.currentThread().sleep(5000);
// continue;
// }
// }
// Thread.currentThread().sleep(Long.MAX_VALUE);
//=============================================================================================================//
try {

b.group(workerGroup);
b.channel(NioSocketChannel.class);
b.option(ChannelOption.SO_KEEPALIVE, true);
b.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new ClientDataSyncClientHandler());
}
});
executeConnect(host,port);
}catch(Exception e){ 
e.printStackTrace();
}finally {
// workerGroup.shutdownGracefully();
}

}
//执行该方法启动timer,每隔一段时间执行connect,连接成功即cancel掉该timer即可
public void executeConnect(String host, int port) throws Exception{
hostTemp = host;
portTemp = port;
timer = new Timer();
timer.schedule(new TimerTask()
{
@Override
public void run() {
tryConnect(hostTemp, portTemp);
System.gc();
}
}, 1000, 10000) ;
}

public void tryConnect(String host, int port){
try{
f = b.connect(host, port);

f.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
flg = true;
System.out.println("客户端连接服务器成功:" + future.isDone());
timer.cancel();
// timeoutTemp.cancel();
} else {
if (future.isCancelled()) {
System.out.println("客户端连接服务器取消");
} else {
System.out.println("客户端连接服务器错误 Success: "
+ future.isSuccess() + " Done: "
+ future.isDone() + " Cause: "
+ future.cause().toString());
}
// Thread.currentThread().sleep(ConfigUtil.getInt("whileExecuteTime"));
}
}
});
}catch(Exception e){
System.out.println("连接服务器失败 ");
e.printStackTrace();
}
}

public void restartClient()throws Exception {
executeConnect(ConfigUtil.getString("remoteServerHost"), ConfigUtil.getInt("remoteServerPort"));
}

public void stopClient() throws Exception{
workerGroup.shutdownGracefully();
}

public void run(){
try {
connect(ConfigUtil.getString("remoteServerHost"), ConfigUtil.getInt("remoteServerPort"));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

public static void main(String args[]) throws Exception{
client.run();
}
}


客户端主handler:

package com.chrhc.projects.uiap.support.jeecg.client;

import com.chrhc.projects.uiap.support.jeecg.common.ConfigUtil;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpRequestEncoder;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseDecoder;
import io.netty.handler.timeout.IdleStateHandler;

public class ClientDataSyncClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpResponse) 
{
HttpResponse response = (HttpResponse) msg;
}
if(msg instanceof HttpContent)
{
HttpContent content = (HttpContent)msg;
ByteBuf buf = content.content();
System.out.println("客户端获取到的response的内容: "+buf.toString(io.netty.util.CharsetUtil.UTF_8));
buf.release();
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.channel().pipeline().remove(this);
ctx.channel().pipeline().addLast(new HttpResponseDecoder());
// 客户端发送的是httprequest,所以要使用HttpRequestEncoder进行编码
ctx.channel().pipeline().addLast(new HttpRequestEncoder());
ctx.channel().pipeline().addLast(new ClientDataSyncClientBizHandler());

ctx.channel().pipeline().addLast("idleStateHandler", new IdleStateHandler(0, 0, ConfigUtil.getInt("heatBeatTime")));
ctx.channel().pipeline().addLast("myHandler", new ClientDataSyncHeartBeatHandler());
ClientDataSyncClientBiz.doBussiness(ctx.channel());
}
}


客户端心跳包发送类:

package com.chrhc.projects.uiap.support.jeecg.client;

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;

import java.net.URI;

import com.chrhc.projects.uiap.support.jeecg.common.ConfigUtil;

public class ClientDataSyncHeartBeatHandler extends ChannelDuplexHandler {
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
IdleStateEvent e = (IdleStateEvent) evt;
if (e.state() == IdleState.READER_IDLE) {
ctx.close();
} else if (e.state() == IdleState.WRITER_IDLE) {
ctx.close();
} else if (e.state() == IdleState.ALL_IDLE) {
URI uri = new URI("http://"+ConfigUtil.getString("remoteServerHost")+":"+ConfigUtil.getInt("remoteServerPort"));
String msg = "ping";
DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
uri.toASCIIString(), Unpooled.wrappedBuffer(msg.getBytes("UTF-8")));

// 构建http请求
request.headers().set(HttpHeaders.Names.HOST, ConfigUtil.getString("remoteServerHost"));
request.headers().set(HttpHeaders.Names.CONTENT_LENGTH, request.content().readableBytes());
// 发送http请求
ctx.writeAndFlush(request);
// channel.flush();
System.out.println("send ping msg");
}
}
}
}


客户端业务处理handler,这个的加入是在客户端主handler  ClientDataSyncClientHandler 中:

package com.chrhc.projects.uiap.support.jeecg.client;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpResponse;

import com.chrhc.projects.uiap.support.jeecg.processor.DbMessageProcessor;

public class ClientDataSyncClientBizHandler extends ChannelInboundHandlerAdapter {
private static String messageCon = "";
public DbMessageProcessor dbmp = new DbMessageProcessor();
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpResponse) 
{
HttpResponse response = (HttpResponse) msg;
// System.out.println("客户端获取到的response的CONTENT_TYPE:" + response.headers().get(HttpHeaders.Names.CONTENT_TYPE));
}
if(msg instanceof HttpContent)
{
HttpContent content = (HttpContent)msg;
ByteBuf buf = content.content();
System.out.println("客户端获取到的response的内容: "+buf.toString(io.netty.util.CharsetUtil.UTF_8));
messageCon = buf.toString(io.netty.util.CharsetUtil.UTF_8);
buf.release();
if(messageCon.length()>12&&messageCon.substring(0, 2).contentEquals("DB")){
System.out.println("开始执行处理");
String flag = messageCon.substring(3, 12);
dbmp.processJsonMsg(messageCon.substring(12),flag);
}
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
ctx.channel().disconnect();
// ctx.channel().closeFuture();
ctx.channel().close();
ctx.close();
ClientDataSyncClient client = ClientDataSyncClient.getInstance();
// client.workerGroup.shutdownGracefully();
System.out.println("服务器已经断开连接了");
client.restartClient();

}
}


客户端业务逻辑处理代码:

package com.chrhc.projects.uiap.support.jeecg.client;

import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpVersion;

import java.net.URI;

import com.chrhc.projects.uiap.support.jeecg.common.ConfigUtil;
import com.chrhc.projects.uiap.support.jeecg.common.LocalIPGetter;

public class ClientDataSyncClientBiz {
public int flag = 0;
public static void doBussiness(Channel channel) throws Exception{
URI uri = new URI("http://"+ConfigUtil.getString("remoteServerHost")+":"+ConfigUtil.getInt("remoteServerPort"));
String msg = LocalIPGetter.getLocalIp()+":"+ConfigUtil.getString("localServerPort");
DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
uri.toASCIIString(), Unpooled.wrappedBuffer(msg.getBytes("UTF-8")));

// 构建http请求
request.headers().set(HttpHeaders.Names.HOST, ConfigUtil.getString("remoteServerHost"));
request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
request.headers().set(HttpHeaders.Names.CONTENT_LENGTH, request.content().readableBytes());
// 发送http请求
channel.pipeline().write(request);
channel.flush();
}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烂泥稀云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值