增加服务端和客户端通讯方式
This commit is contained in:
parent
b07d7d61ac
commit
f07c034b0e
6
pom.xml
6
pom.xml
|
@ -281,6 +281,12 @@
|
||||||
<groupId>org.flywaydb</groupId>
|
<groupId>org.flywaydb</groupId>
|
||||||
<artifactId>flyway-core</artifactId>
|
<artifactId>flyway-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!--netty-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-all</artifactId>
|
||||||
|
<version>5.0.0.Alpha2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
package com.luckyframe;
|
package com.luckyframe;
|
||||||
|
|
||||||
|
import com.luckyframe.common.netty.NettyServer;
|
||||||
import org.mybatis.spring.annotation.MapperScan;
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.CommandLineRunner;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
|
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启动LuckyFrameWeb程序
|
* 启动LuckyFrameWeb程序
|
||||||
* =================================================================
|
* =================================================================
|
||||||
|
@ -17,12 +25,34 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||||
*/
|
*/
|
||||||
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class,FlywayAutoConfiguration.class })
|
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class,FlywayAutoConfiguration.class })
|
||||||
@MapperScan("com.luckyframe.project.*.*.mapper")
|
@MapperScan("com.luckyframe.project.*.*.mapper")
|
||||||
public class LuckyFrameWebApplication
|
public class LuckyFrameWebApplication implements CommandLineRunner
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@Value("${netty.port}")
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
@Value("${netty.url}")
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private NettyServer server;
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(LuckyFrameWebApplication.class);
|
||||||
|
|
||||||
public static void main(String[] args)
|
public static void main(String[] args)
|
||||||
{
|
{
|
||||||
System.setProperty("spring.devtools.restart.enabled", "false");
|
System.setProperty("spring.devtools.restart.enabled", "false");
|
||||||
SpringApplication.run(LuckyFrameWebApplication.class, args);
|
SpringApplication.run(LuckyFrameWebApplication.class, args);
|
||||||
System.out.println("LuckyFrameWeb启动成功......");
|
System.out.println("LuckyFrameWeb启动成功......");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(String... args) throws Exception {
|
||||||
|
InetSocketAddress address = new InetSocketAddress(url,port);
|
||||||
|
System.out.println("服务端启动成功:"+url+":"+port);
|
||||||
|
server.start(address);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.luckyframe.common.netty;
|
||||||
|
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
|
||||||
|
public class ChannelMap {
|
||||||
|
private static Map<String, Channel> channelMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private static Map<String, Lock> channelLockMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public static void setChannel(String key,Channel channel){
|
||||||
|
channelMap.put(key,channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Channel getChannel(String key){
|
||||||
|
return channelMap.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setChannelLock(String key,Lock lock){
|
||||||
|
channelLockMap.put(key,lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Lock getChannelLock(String key){
|
||||||
|
return channelLockMap.get(key);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package com.luckyframe.common.netty;
|
||||||
|
|
||||||
|
import com.luckyframe.project.system.client.domain.Client;
|
||||||
|
import com.luckyframe.project.system.client.mapper.ClientMapper;
|
||||||
|
import com.luckyframe.project.system.client.service.IClientService;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class NettyChannelMap {
|
||||||
|
//logger
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(NettyChannelMap.class);
|
||||||
|
|
||||||
|
private static Map<String, SocketChannel> map=new ConcurrentHashMap<String, SocketChannel>();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IClientService clientService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ClientMapper clientMapper;
|
||||||
|
|
||||||
|
public void add(String clientId,SocketChannel socketChannel){
|
||||||
|
map.put(clientId,socketChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Channel get(String clientId){
|
||||||
|
return map.get(clientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(SocketChannel socketChannel){
|
||||||
|
for (Map.Entry entry:map.entrySet()){
|
||||||
|
if (entry.getValue()==socketChannel){
|
||||||
|
log.info("#############客户端下线##############");
|
||||||
|
log.info("下线主机名为:"+entry.getKey());
|
||||||
|
Client client=clientService.selectClientByClientName(entry.getKey().toString());
|
||||||
|
if(client!=null)
|
||||||
|
{
|
||||||
|
client.setStatus(1);
|
||||||
|
clientMapper.updateClient(client);
|
||||||
|
//登陆失败,删除心跳map中的数据
|
||||||
|
NettyServer.clientMap.remove(client.getClientName());
|
||||||
|
}
|
||||||
|
map.remove(entry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
package com.luckyframe.common.netty;
|
||||||
|
|
||||||
|
import io.netty.bootstrap.ServerBootstrap;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.ChannelOption;
|
||||||
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class NettyServer {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ServerChannelInitializer serverChannelInitializer;
|
||||||
|
|
||||||
|
//logger
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(NettyServer.class);
|
||||||
|
|
||||||
|
public static final HashMap<String,String> clientMap=new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
public void start(InetSocketAddress address){
|
||||||
|
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
|
||||||
|
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||||
|
try {
|
||||||
|
ServerBootstrap bootstrap = new ServerBootstrap()
|
||||||
|
.group(bossGroup,workerGroup)
|
||||||
|
.channel(NioServerSocketChannel.class)
|
||||||
|
.childOption(ChannelOption.SO_KEEPALIVE, true)
|
||||||
|
.option(ChannelOption.SO_BACKLOG, 1024)
|
||||||
|
.childHandler(serverChannelInitializer);
|
||||||
|
// 绑定端口,开始接收进来的连接
|
||||||
|
ChannelFuture future = bootstrap.bind(address).sync();
|
||||||
|
log.info("服务端启动成功,监听端口 " + address.getPort());
|
||||||
|
future.channel().closeFuture().sync();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
bossGroup.shutdownGracefully();
|
||||||
|
workerGroup.shutdownGracefully();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Result write(Object obj, String tenantId ,String uniId) throws Exception {
|
||||||
|
// 获取锁
|
||||||
|
Lock lock = ChannelMap.getChannelLock(tenantId);
|
||||||
|
try {
|
||||||
|
Channel channel = ChannelMap.getChannel(tenantId);
|
||||||
|
if(channel != null){
|
||||||
|
lock.lock();
|
||||||
|
if(channel.isOpen()){
|
||||||
|
// 设置同步
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
ServerHandler nettyServerHandler = (ServerHandler) channel.pipeline().get("handler");
|
||||||
|
nettyServerHandler.resetSync(latch,1);
|
||||||
|
nettyServerHandler.setUnidId(uniId);
|
||||||
|
channel.writeAndFlush(obj).sync();
|
||||||
|
//同步返回结果
|
||||||
|
if (latch.await(60, TimeUnit.SECONDS)){
|
||||||
|
// printerServerHandler.setTimeout(0);
|
||||||
|
return nettyServerHandler.getResult();
|
||||||
|
}
|
||||||
|
//如果超时,将超时标志设置为1
|
||||||
|
//printerServerHandler.setTimeout(1);
|
||||||
|
log.error("netty请求超时60s");
|
||||||
|
return new Result(2,"请求超时",null);
|
||||||
|
}else{
|
||||||
|
return new Result(0,"客户端已关闭!",null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
return new Result(0,"服务出错!",null);
|
||||||
|
|
||||||
|
}finally {
|
||||||
|
if (lock != null){
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Result(0,"客户端没有连接!",null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package com.luckyframe.common.netty;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
|
||||||
|
public class Result implements Serializable {
|
||||||
|
private int code;
|
||||||
|
private Object message;
|
||||||
|
private String uniId;
|
||||||
|
|
||||||
|
public Result(int code, Object message, String uniId) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
this.uniId = uniId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCode(int code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(Object message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUniId() {
|
||||||
|
return uniId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUniId(String uniId) {
|
||||||
|
this.uniId = uniId;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.luckyframe.common.netty;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
|
||||||
|
import io.netty.handler.codec.string.StringDecoder;
|
||||||
|
import io.netty.handler.codec.string.StringEncoder;
|
||||||
|
import io.netty.handler.timeout.IdleStateHandler;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {
|
||||||
|
@Autowired
|
||||||
|
private ServerHandler serverHandler;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initChannel(SocketChannel channel) throws Exception {
|
||||||
|
ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes());
|
||||||
|
channel.pipeline().addLast(new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, delimiter));
|
||||||
|
channel.pipeline().addLast("decoder",new StringDecoder(Charset.forName("GBK")));
|
||||||
|
channel.pipeline().addLast("encoder",new StringEncoder(Charset.forName("UTF-8")));
|
||||||
|
channel.pipeline().addLast(new IdleStateHandler(30,0,0,TimeUnit.SECONDS));
|
||||||
|
channel.pipeline().addLast("handler", serverHandler);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,252 @@
|
||||||
|
package com.luckyframe.common.netty;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.luckyframe.common.constant.JobConstants;
|
||||||
|
import com.luckyframe.common.constant.ScheduleConstants;
|
||||||
|
import com.luckyframe.framework.config.LuckyFrameConfig;
|
||||||
|
import com.luckyframe.project.monitor.job.domain.Job;
|
||||||
|
import com.luckyframe.project.monitor.job.mapper.JobMapper;
|
||||||
|
import com.luckyframe.project.monitor.job.service.IJobService;
|
||||||
|
import com.luckyframe.project.monitor.job.util.ScheduleUtils;
|
||||||
|
import com.luckyframe.project.system.client.domain.Client;
|
||||||
|
import com.luckyframe.project.system.client.mapper.ClientMapper;
|
||||||
|
import com.luckyframe.project.system.client.service.IClientService;
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import io.netty.handler.timeout.IdleState;
|
||||||
|
import io.netty.handler.timeout.IdleStateEvent;
|
||||||
|
import org.quartz.CronTrigger;
|
||||||
|
import org.quartz.Scheduler;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
@Component("ServerHandler")
|
||||||
|
@ChannelHandler.Sharable
|
||||||
|
public class ServerHandler extends ChannelInboundHandlerAdapter {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ClientMapper clientMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private LuckyFrameConfig lfConfig;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IClientService clientService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IJobService jobService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private NettyChannelMap nettyChannelMap;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private JobMapper jobMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Scheduler scheduler;
|
||||||
|
|
||||||
|
private ChannelHandlerContext ctx;
|
||||||
|
|
||||||
|
private CountDownLatch latch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息的唯一ID
|
||||||
|
*/
|
||||||
|
private String unidId = "";
|
||||||
|
/**
|
||||||
|
* 同步标志
|
||||||
|
*/
|
||||||
|
private int rec;
|
||||||
|
/**
|
||||||
|
* 客户端返回的结果
|
||||||
|
*/
|
||||||
|
private Result result;
|
||||||
|
/**
|
||||||
|
* 心跳丢失次数
|
||||||
|
*/
|
||||||
|
private int counter = 0;
|
||||||
|
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ServerHandler.class);
|
||||||
|
@Override
|
||||||
|
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||||
|
JSONObject json= JSON.parseObject(msg.toString());
|
||||||
|
/* log.info("心跳发送成功!");*/
|
||||||
|
if("clientUp".equals(json.get("method")))
|
||||||
|
{
|
||||||
|
ChannelMap.setChannel(json.get("hostName").toString(),ctx.channel());
|
||||||
|
ChannelMap.setChannelLock(json.get("hostName").toString(),new ReentrantLock());
|
||||||
|
//返回接受成功消息
|
||||||
|
JSONObject tmp=new JSONObject();
|
||||||
|
tmp.put("method","return");
|
||||||
|
tmp.put("message","收到消息");
|
||||||
|
tmp.put("success","1");
|
||||||
|
ctx.writeAndFlush(tmp.toString());
|
||||||
|
|
||||||
|
//接收到客户端上线消息
|
||||||
|
log.info("#############客户端上线##############");
|
||||||
|
log.info("上线主机名为:"+json.get("hostName"));
|
||||||
|
String hostName=json.get("hostName").toString();
|
||||||
|
String clientIp=ctx.channel().remoteAddress().toString();
|
||||||
|
//检查客户端是否已经注册入库
|
||||||
|
Client client=clientService.selectClientByClientName(hostName);
|
||||||
|
if(client==null)
|
||||||
|
{
|
||||||
|
client = new Client();
|
||||||
|
client.setClientIp(hostName);
|
||||||
|
client.setClientName(hostName);
|
||||||
|
client.setCheckinterval(30);
|
||||||
|
client.setClientPath("/TestDriven");
|
||||||
|
}
|
||||||
|
if(client.getClientId()==null)
|
||||||
|
{
|
||||||
|
//未注册则自动注册入库
|
||||||
|
int result = 0;
|
||||||
|
Job job=new Job();
|
||||||
|
job.setJobName(JobConstants.JOB_JOBNAME_FOR_CLIENTHEART);
|
||||||
|
job.setJobGroup(JobConstants.JOB_GROUPNAME_FOR_CLIENTHEART);
|
||||||
|
job.setMethodName(JobConstants.JOB_METHODNAME_FOR_CLIENTHEART);
|
||||||
|
job.setMethodParams(client.getClientIp());
|
||||||
|
job.setCronExpression("0/"+client.getCheckinterval().toString()+" * * * * ? ");
|
||||||
|
job.setMisfirePolicy(ScheduleConstants.MISFIRE_DO_NOTHING);
|
||||||
|
job.setStatus(JobConstants.JOB_STATUS_FOR_CLIENTHEART);
|
||||||
|
job.setRemark("");
|
||||||
|
/*在公共调度表中插入数据*/
|
||||||
|
result = jobMapper.insertJob(job);
|
||||||
|
if(result<1){
|
||||||
|
//登录失败,断开连接
|
||||||
|
ctx.close();
|
||||||
|
throw new Exception("新增客户端时无法插入任务调度表");
|
||||||
|
}
|
||||||
|
//更新jobLis
|
||||||
|
CronTrigger cronTrigger = ScheduleUtils.getCronTrigger(scheduler, job.getJobId());
|
||||||
|
// 如果不存在,则创建
|
||||||
|
if (cronTrigger == null)
|
||||||
|
{
|
||||||
|
ScheduleUtils.createScheduleJob(scheduler, job);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScheduleUtils.updateScheduleJob(scheduler, job, cronTrigger);
|
||||||
|
}
|
||||||
|
/*在调度预约表中插入数据*/
|
||||||
|
client.setJobId(job.getJobId().intValue());
|
||||||
|
client.setClientIp(hostName);
|
||||||
|
client.setClientName(hostName);
|
||||||
|
clientService.insertClient(client);
|
||||||
|
log.info("主机名为:"+json.get("hostName")+"自动注册成功");
|
||||||
|
}
|
||||||
|
if(lfConfig.getVersion().equals(json.get("version"))){
|
||||||
|
//版本号一致
|
||||||
|
client.setClientIp(hostName);
|
||||||
|
client.setClientName(hostName);
|
||||||
|
client.setRemark("检测客户端状态成功");
|
||||||
|
client.setStatus(0);
|
||||||
|
clientMapper.updateClient(client);
|
||||||
|
//登录成功,把channel存到服务端的map中
|
||||||
|
nettyChannelMap.add(hostName,(SocketChannel)ctx.channel());
|
||||||
|
//登陆成功,放入map中用于心跳
|
||||||
|
NettyServer.clientMap.put(hostName,"0");
|
||||||
|
}else{
|
||||||
|
client.setClientIp(hostName);
|
||||||
|
client.setClientName(hostName);
|
||||||
|
client.setRemark("客户端("+json.get("version")+")与服务器("+lfConfig.getVersion()+")版本不一致");
|
||||||
|
client.setStatus(1);
|
||||||
|
clientMapper.updateClient(client);
|
||||||
|
//登陆失败,删除心跳map中的数据
|
||||||
|
NettyServer.clientMap.remove(hostName);
|
||||||
|
//登录失败,断开连接
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if("return".equals(json.get("method")))
|
||||||
|
{
|
||||||
|
Result re =JSONObject.parseObject(json.get("data").toString(),Result.class);
|
||||||
|
//校验返回的信息是否是同一个信息
|
||||||
|
if (unidId.equals(re.getUniId())){
|
||||||
|
latch.countDown();//消息返回完毕,释放同步锁,具体业务需要判断指令是否匹配
|
||||||
|
rec = 0;
|
||||||
|
result = re;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if("ping".equals(json.get("method")))
|
||||||
|
{
|
||||||
|
String hostName=json.get("hostName").toString();
|
||||||
|
if(NettyServer.clientMap.get(hostName)==null||(!"0".equals(NettyServer.clientMap.get(hostName))))
|
||||||
|
{
|
||||||
|
//检查客户端是否已经注册入库
|
||||||
|
Client client=clientService.selectClientByClientName(hostName);
|
||||||
|
//版本号一致
|
||||||
|
client.setClientIp(hostName);
|
||||||
|
client.setClientName(hostName);
|
||||||
|
client.setRemark("检测客户端状态成功");
|
||||||
|
client.setStatus(0);
|
||||||
|
clientMapper.updateClient(client);
|
||||||
|
//更新客户端状态成功
|
||||||
|
NettyServer.clientMap.put(hostName,"0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//刷新缓存区
|
||||||
|
ctx.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
|
cause.printStackTrace();
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
//channel失效,从Map中移除
|
||||||
|
nettyChannelMap.remove((SocketChannel)ctx.channel());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
||||||
|
if (evt instanceof IdleStateEvent) {
|
||||||
|
IdleStateEvent event = (IdleStateEvent) evt;
|
||||||
|
if (event.state().equals(IdleState.READER_IDLE)){
|
||||||
|
// 空闲40s之后触发 (心跳包丢失)
|
||||||
|
if (counter >= 3) {
|
||||||
|
// 连续丢失3个心跳包 (断开连接)
|
||||||
|
ctx.channel().close().sync();
|
||||||
|
log.error("已与"+ctx.channel().remoteAddress()+"断开连接");
|
||||||
|
} else {
|
||||||
|
counter++;
|
||||||
|
log.debug(ctx.channel().remoteAddress() + "丢失了第 " + counter + " 个心跳包");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
super.channelActive(ctx);
|
||||||
|
this.ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetSync(CountDownLatch latch, int rec) {
|
||||||
|
this.latch = latch;
|
||||||
|
this.rec = rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnidId(String s){
|
||||||
|
this.unidId = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -16,7 +16,11 @@ import java.security.KeyManagementException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.luckyframe.common.netty.NettyServer;
|
||||||
|
import com.luckyframe.common.netty.Result;
|
||||||
import org.apache.http.HttpEntity;
|
import org.apache.http.HttpEntity;
|
||||||
import org.apache.http.NoHttpResponseException;
|
import org.apache.http.NoHttpResponseException;
|
||||||
import org.apache.http.client.config.RequestConfig;
|
import org.apache.http.client.config.RequestConfig;
|
||||||
|
@ -47,6 +51,38 @@ public class HttpRequest {
|
||||||
* @date 2019年5月14日
|
* @date 2019年5月14日
|
||||||
*/
|
*/
|
||||||
public static String httpClientPost(String urlParam,String jsonparams,Integer socketTimeout) throws NoSuchAlgorithmException, KeyManagementException, UnsupportedEncodingException, IOException{
|
public static String httpClientPost(String urlParam,String jsonparams,Integer socketTimeout) throws NoSuchAlgorithmException, KeyManagementException, UnsupportedEncodingException, IOException{
|
||||||
|
//测试netty同步等待
|
||||||
|
if(urlParam.contains("netty"))
|
||||||
|
{
|
||||||
|
int firstIndex=urlParam.indexOf("netty");
|
||||||
|
int lastIndex=urlParam.lastIndexOf(":");
|
||||||
|
String clientId=urlParam.substring(firstIndex,lastIndex);
|
||||||
|
JSONObject tmp=new JSONObject();
|
||||||
|
String uuid= UUID.randomUUID().toString();
|
||||||
|
//封装调度参数
|
||||||
|
String tmpMethod=urlParam.substring(lastIndex+5);
|
||||||
|
tmp.put("method","run");
|
||||||
|
tmp.put("data",jsonparams);
|
||||||
|
tmp.put("uuid",uuid);
|
||||||
|
tmp.put("url",tmpMethod);
|
||||||
|
tmp.put("getOrPost","post");
|
||||||
|
tmp.put("socketTimeout",socketTimeout);
|
||||||
|
Result re= null;
|
||||||
|
try {
|
||||||
|
re = NettyServer.write(tmp.toString(),clientId, uuid);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if(1==re.getCode())
|
||||||
|
{
|
||||||
|
//请求成功,返回结果
|
||||||
|
return (String)re.getMessage();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
StringBuffer resultBuffer = null;
|
StringBuffer resultBuffer = null;
|
||||||
CloseableHttpClient httpclient=HttpClients.createDefault();
|
CloseableHttpClient httpclient=HttpClients.createDefault();
|
||||||
HttpPost httpPost = new HttpPost(urlParam);
|
HttpPost httpPost = new HttpPost(urlParam);
|
||||||
|
@ -106,6 +142,38 @@ public class HttpRequest {
|
||||||
* @date 2019年5月14日
|
* @date 2019年5月14日
|
||||||
*/
|
*/
|
||||||
public static String httpClientGet(String urlParam, Map<String, Object> params,Integer socketTimeout) throws NoSuchAlgorithmException, KeyManagementException,NoHttpResponseException {
|
public static String httpClientGet(String urlParam, Map<String, Object> params,Integer socketTimeout) throws NoSuchAlgorithmException, KeyManagementException,NoHttpResponseException {
|
||||||
|
//测试netty同步等待
|
||||||
|
if(urlParam.contains("netty"))
|
||||||
|
{
|
||||||
|
int firstIndex=urlParam.indexOf("netty");
|
||||||
|
int lastIndex=urlParam.lastIndexOf(":");
|
||||||
|
String clientId=urlParam.substring(firstIndex,lastIndex);
|
||||||
|
JSONObject tmp=new JSONObject();
|
||||||
|
String uuid= UUID.randomUUID().toString();
|
||||||
|
//封装调度参数
|
||||||
|
String tmpMethod=urlParam.substring(lastIndex+5);
|
||||||
|
tmp.put("method","run");
|
||||||
|
tmp.put("data",params);
|
||||||
|
tmp.put("uuid",uuid);
|
||||||
|
tmp.put("url",tmpMethod);
|
||||||
|
tmp.put("getOrPost","get");
|
||||||
|
tmp.put("socketTimeout",socketTimeout);
|
||||||
|
Result re= null;
|
||||||
|
try {
|
||||||
|
re = NettyServer.write(tmp.toString(),clientId, uuid);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if(1==re.getCode())
|
||||||
|
{
|
||||||
|
//请求成功,返回结果
|
||||||
|
return (String)re.getMessage();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
StringBuffer resultBuffer = null;
|
StringBuffer resultBuffer = null;
|
||||||
CloseableHttpClient httpclient=HttpClients.createDefault();
|
CloseableHttpClient httpclient=HttpClients.createDefault();
|
||||||
BufferedReader br = null;
|
BufferedReader br = null;
|
||||||
|
@ -170,6 +238,37 @@ public class HttpRequest {
|
||||||
* @date 2019年3月15日
|
* @date 2019年3月15日
|
||||||
*/
|
*/
|
||||||
public static String httpClientUploadFile(String urlParam, String loadpath, File file) throws NoSuchAlgorithmException, KeyManagementException, HttpHostConnectException {
|
public static String httpClientUploadFile(String urlParam, String loadpath, File file) throws NoSuchAlgorithmException, KeyManagementException, HttpHostConnectException {
|
||||||
|
//测试netty同步等待
|
||||||
|
if(urlParam.contains("netty"))
|
||||||
|
{
|
||||||
|
int firstIndex=urlParam.indexOf("netty");
|
||||||
|
int lastIndex=urlParam.lastIndexOf(":");
|
||||||
|
String clientId=urlParam.substring(firstIndex,lastIndex);
|
||||||
|
JSONObject tmp=new JSONObject();
|
||||||
|
String uuid= UUID.randomUUID().toString();
|
||||||
|
//封装调度参数
|
||||||
|
String tmpMethod=urlParam.substring(lastIndex+5);
|
||||||
|
tmp.put("method","download");
|
||||||
|
tmp.put("path",loadpath);
|
||||||
|
tmp.put("fileName",file.getName());
|
||||||
|
tmp.put("uuid",uuid);
|
||||||
|
tmp.put("url",tmpMethod);
|
||||||
|
Result re= null;
|
||||||
|
try {
|
||||||
|
re = NettyServer.write(tmp.toString(),clientId, uuid);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if(1==re.getCode())
|
||||||
|
{
|
||||||
|
//请求成功,返回结果
|
||||||
|
return "上传成功";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
StringBuffer resultBuffer = null;
|
StringBuffer resultBuffer = null;
|
||||||
CloseableHttpClient httpclient=HttpClients.createDefault();
|
CloseableHttpClient httpclient=HttpClients.createDefault();
|
||||||
HttpPost httpPost = new HttpPost(urlParam);
|
HttpPost httpPost = new HttpPost(urlParam);
|
||||||
|
|
|
@ -100,6 +100,8 @@ public class ClientHeart {
|
||||||
}
|
}
|
||||||
} catch (RuntimeException | KeyManagementException | NoSuchAlgorithmException | NoHttpResponseException e) {
|
} catch (RuntimeException | KeyManagementException | NoSuchAlgorithmException | NoHttpResponseException e) {
|
||||||
if (null==ClientHeart.getClientStatus(params) || ClientHeart.getClientStatus(params) != 1) {
|
if (null==ClientHeart.getClientStatus(params) || ClientHeart.getClientStatus(params) != 1) {
|
||||||
|
if(params.contains("nettyClient-"))
|
||||||
|
return;
|
||||||
Client client = new Client();
|
Client client = new Client();
|
||||||
client.setClientIp(params);
|
client.setClientIp(params);
|
||||||
client.setRemark("检测客户端远程异常");
|
client.setRemark("检测客户端远程异常");
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.luckyframe.project.system.client.controller;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.luckyframe.common.netty.NettyServer;
|
||||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
@ -47,7 +48,7 @@ import com.luckyframe.project.system.project.service.IProjectService;
|
||||||
public class ClientController extends BaseController
|
public class ClientController extends BaseController
|
||||||
{
|
{
|
||||||
private String prefix = "system/client";
|
private String prefix = "system/client";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IClientService clientService;
|
private IClientService clientService;
|
||||||
|
|
||||||
|
@ -192,6 +193,8 @@ public class ClientController extends BaseController
|
||||||
return AjaxResult.error();
|
return AjaxResult.error();
|
||||||
}
|
}
|
||||||
client.setRemark("修改客户端信息,重新初始化");
|
client.setRemark("修改客户端信息,重新初始化");
|
||||||
|
//更新数据,删除心跳map中的数据
|
||||||
|
NettyServer.clientMap.remove(client.getClientName());
|
||||||
return toAjax(clientService.updateClient(client));
|
return toAjax(clientService.updateClient(client));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,6 +209,11 @@ public class ClientController extends BaseController
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
String[] idList=ids.split(",");
|
||||||
|
for (String s : idList) {
|
||||||
|
Client client = clientService.selectClientById(Integer.valueOf(s));
|
||||||
|
NettyServer.clientMap.remove(client.getClientName());
|
||||||
|
}
|
||||||
return toAjax(clientService.deleteClientByIds(ids));
|
return toAjax(clientService.deleteClientByIds(ids));
|
||||||
}
|
}
|
||||||
catch (BusinessException e)
|
catch (BusinessException e)
|
||||||
|
|
|
@ -85,4 +85,12 @@ public interface ClientMapper
|
||||||
* @date 2019年2月25日
|
* @date 2019年2月25日
|
||||||
*/
|
*/
|
||||||
public Client checkIpUnique(String clientIp);
|
public Client checkIpUnique(String clientIp);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据客户端名称查找客户端
|
||||||
|
* @param clientName
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Client selectClientByClientName(String clientName);
|
||||||
}
|
}
|
|
@ -271,4 +271,10 @@ public class ClientServiceImpl implements IClientService
|
||||||
}
|
}
|
||||||
return returnClientProjects;
|
return returnClientProjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Client selectClientByClientName(String clientName) {
|
||||||
|
Client info = clientMapper.selectClientByClientName(clientName);
|
||||||
|
return info;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,4 +96,12 @@ public interface IClientService
|
||||||
* @date 2019年3月14日
|
* @date 2019年3月14日
|
||||||
*/
|
*/
|
||||||
public List<Client> selectClientsByProjectId(int projectId);
|
public List<Client> selectClientsByProjectId(int projectId);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据客户端名称查找客户端
|
||||||
|
* @param clientName
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Client selectClientByClientName(String clientName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ spring:
|
||||||
master:
|
master:
|
||||||
url: jdbc:mysql://localhost:3306/luckyframe?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
url: jdbc:mysql://localhost:3306/luckyframe?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
username: root
|
username: root
|
||||||
password:
|
password:
|
||||||
# 从库数据源
|
# 从库数据源
|
||||||
slave:
|
slave:
|
||||||
# 从数据源开关/默认关闭
|
# 从数据源开关/默认关闭
|
||||||
|
|
|
@ -8,7 +8,10 @@ luckyframe:
|
||||||
copyrightYear: 2019
|
copyrightYear: 2019
|
||||||
# 获取ip地址开关
|
# 获取ip地址开关
|
||||||
addressEnabled: true
|
addressEnabled: true
|
||||||
|
# netty配置
|
||||||
|
netty:
|
||||||
|
url: 0.0.0.0
|
||||||
|
port: 7070
|
||||||
# 开发环境配置
|
# 开发环境配置
|
||||||
server:
|
server:
|
||||||
# 服务端口
|
# 服务端口
|
||||||
|
|
|
@ -102,4 +102,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
<select id="checkIpUnique" parameterType="String" resultMap="ClientResult">
|
<select id="checkIpUnique" parameterType="String" resultMap="ClientResult">
|
||||||
select client_id, job_id, client_ip from sys_client where client_ip=#{client_ip}
|
select client_id, job_id, client_ip from sys_client where client_ip=#{client_ip}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectClientByClientName" parameterType="String" resultMap="ClientResult">
|
||||||
|
select client_id, job_id, client_name,status from sys_client where client_name=#{clientName} limit 1
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
|
@ -79,7 +79,6 @@
|
||||||
},
|
},
|
||||||
clientIp:{
|
clientIp:{
|
||||||
required:true,
|
required:true,
|
||||||
isIp:true,
|
|
||||||
remote: {
|
remote: {
|
||||||
url: ctx + "system/client/checkIpUnique",
|
url: ctx + "system/client/checkIpUnique",
|
||||||
type: "post",
|
type: "post",
|
||||||
|
|
Loading…
Reference in New Issue