diff --git a/pom.xml b/pom.xml index 83b9dab..37c366a 100644 --- a/pom.xml +++ b/pom.xml @@ -33,5 +33,11 @@ okhttp 4.9.3 + + + io.netty + netty-all + 4.1.68.Final + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 83b9dab..37c366a 100644 --- a/pom.xml +++ b/pom.xml @@ -33,5 +33,11 @@ okhttp 4.9.3 + + + io.netty + netty-all + 4.1.68.Final + \ No newline at end of file diff --git a/src/main/java/com/casic/swing/ui/TimeGuardNtp.form b/src/main/java/com/casic/swing/ui/TimeGuardNtp.form index ce81e35..3bf4535 100644 --- a/src/main/java/com/casic/swing/ui/TimeGuardNtp.form +++ b/src/main/java/com/casic/swing/ui/TimeGuardNtp.form @@ -44,7 +44,7 @@ - + @@ -55,7 +55,7 @@ - + @@ -87,20 +87,6 @@ - - - - - - - - - - - - - - @@ -133,7 +119,7 @@ - + @@ -153,7 +139,7 @@ - + @@ -163,7 +149,7 @@ - + @@ -173,7 +159,7 @@ - + @@ -181,6 +167,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 83b9dab..37c366a 100644 --- a/pom.xml +++ b/pom.xml @@ -33,5 +33,11 @@ okhttp 4.9.3 + + + io.netty + netty-all + 4.1.68.Final + \ No newline at end of file diff --git a/src/main/java/com/casic/swing/ui/TimeGuardNtp.form b/src/main/java/com/casic/swing/ui/TimeGuardNtp.form index ce81e35..3bf4535 100644 --- a/src/main/java/com/casic/swing/ui/TimeGuardNtp.form +++ b/src/main/java/com/casic/swing/ui/TimeGuardNtp.form @@ -44,7 +44,7 @@ - + @@ -55,7 +55,7 @@ - + @@ -87,20 +87,6 @@ - - - - - - - - - - - - - - @@ -133,7 +119,7 @@ - + @@ -153,7 +139,7 @@ - + @@ -163,7 +149,7 @@ - + @@ -173,7 +159,7 @@ - + @@ -181,6 +167,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/com/casic/swing/ui/TimeGuardNtp.java b/src/main/java/com/casic/swing/ui/TimeGuardNtp.java index 99913c8..aebd36e 100644 --- a/src/main/java/com/casic/swing/ui/TimeGuardNtp.java +++ b/src/main/java/com/casic/swing/ui/TimeGuardNtp.java @@ -4,6 +4,12 @@ import com.alibaba.fastjson.JSONObject; import com.casic.swing.utils.*; import com.google.common.util.concurrent.ThreadFactoryBuilder; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.DatagramPacket; +import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.util.CharsetUtil; import okhttp3.Request; import javax.swing.*; @@ -11,6 +17,7 @@ import java.net.InetAddress; import java.util.List; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -28,12 +35,16 @@ private JComboBox localHostBox; private JCheckBox autoCheckBox; private JButton updateTimeButton; + private JLabel udpPortLabel; + private JLabel udpPortTitle; - private final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor( - 1, new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build()); + private final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build()); + private ScheduledFuture future; private boolean hasNtp = false; private final String serverConfig; + private boolean isTaskRunning = false; + public static void main(String[] args) { new TimeGuardNtp(); } @@ -48,9 +59,9 @@ setLocationRelativeTo(null); setVisible(true); stateView.setText("未同步"); + recentlyTimeLabel.setText("无法确定最近同步时间"); setStateView(Color.GRAY); - ConfigHelper.saveConfig(); //检查环境 new SwingWorker() { @@ -71,35 +82,17 @@ } }.execute(); + // 获取后台地址的配置 serverConfig = ConfigHelper.getConfigData(); - /** - * 时间间隔,单位为毫秒 - * */ - currentTimeLabel.setForeground(Color.BLUE); - new Timer(1000, e -> { - String systemTime = TimeOrDateUtil.timestampToTime(); - currentTimeLabel.setText(systemTime); - }).start(); - String ntpTime = LogToFile.load(); - if (!"".equals(ntpTime)) { - recentlyTimeLabel.setText(ntpTime); - } else { - recentlyTimeLabel.setText("无法确定最近同步时间"); - } + // 每秒更新当前时间 + updateCurrentTimePerSecond(); - Request request = new Request.Builder().url(serverConfig + Constant.FREQUENCY_URL).build(); - HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { - @Override - public void onSuccess(String s) { - frequencyLabel.setText(StringHelper.parseJson(s)); - } + // 获取同步时间参数 + getParamTimeSync(); - @Override - public void onFailure(Exception e) { - - } - }); + // 获取监听的udp端口 + getParamCmdUdpPort(); //初始化JComboBox List addressList = HttpRequestHelper.localHost(); @@ -107,21 +100,28 @@ localHostBox.addItem(address.getHostAddress()); } + // 绑定自动同步复选框事件 autoCheckBox.addActionListener(e -> { JCheckBox checkBox = (JCheckBox) e.getSource(); if (checkBox.isSelected()) { updateTimeButton.setEnabled(false); hostTextField.setEnabled(false); - /** - * 开启同步,只能开启一个同步线程 - * - * scheduleAtFixedRate - * 是以上一个任务开始的时间计时,period时间过去后,检测上一个任务是否执行完毕 - * 如果上一个任务执行完毕,则当前任务立即执行 - * 如果上一个任务没有执行完毕,则需要等上一个任务执行完毕后立即执行 - * */ - executorService.scheduleAtFixedRate(this::updateView, 0, Integer.parseInt(frequencyLabel.getText()), TimeUnit.MINUTES); + + String host = hostTextField.getText().trim(); + if (host.isEmpty()) { + autoCheckBox.setSelected(false); + updateTimeButton.setEnabled(true); + hostTextField.setEnabled(true); + JOptionPane.showMessageDialog(ntpPanel, "授时中心服务器输入错误,请检查", "Runtime Error", JOptionPane.ERROR_MESSAGE); + return; + } + + // 立即执行一次任务 + future = executorService.schedule(this::updateView, 1, TimeUnit.SECONDS); } else { + if (null != future) { + future.cancel(true); + } updateTimeButton.setEnabled(true); hostTextField.setEnabled(true); } @@ -135,13 +135,29 @@ String host = hostTextField.getText().trim(); if (host.isEmpty()) { autoCheckBox.setSelected(false); + updateTimeButton.setEnabled(true); + hostTextField.setEnabled(true); JOptionPane.showMessageDialog(ntpPanel, "授时中心服务器输入错误,请检查", "Runtime Error", JOptionPane.ERROR_MESSAGE); return; } + + if (null != future) { + future.cancel(false); + } + + // 重新获取同步周期 + getParamTimeSync(); + // String result = CommandUtil.simulateNtpResult(); String result = CommandUtil.ntpDate(host); LogToFile.save(result); + // 重新启动定时任务 + if (autoCheckBox.isSelected() == true) { + future = executorService.schedule(this::updateView, Integer.parseInt(frequencyLabel.getText()) * 60 - 5, TimeUnit.SECONDS); + } + + // 向后台接口提交ntp同步校时的结果 JSONObject object = new JSONObject(); if ("".equals(result)) { setStateView(Color.RED); @@ -184,15 +200,14 @@ .post(HttpRequestHelper.createRequestBody(object.toJSONString())) .build(); HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { - @Override public void onSuccess(String s) { - + System.out.println("保存同步结果成功:" + object.get("deltaTime")); } @Override public void onFailure(Exception e) { - e.printStackTrace(); + System.out.println("保存同步结果失败:" + e.getMessage()); } }); } @@ -202,4 +217,83 @@ dotPanel.setPreferredSize(new Dimension(15, 15)); dotPanel.setBackground(color); } + + private void getParamTimeSync() { + Request request = new Request.Builder().url(serverConfig + Constant.FREQUENCY_URL).build(); + HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { + @Override + public void onSuccess(String s) { + frequencyLabel.setText(StringHelper.parseJson(s)); + } + + @Override + public void onFailure(Exception e) { + + } + }); + } + + private void getParamCmdUdpPort() { + Request request = new Request.Builder().url(serverConfig + Constant.CMD_UDP_PORT).build(); + HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { + @Override + public void onSuccess(String s) { + udpPortLabel.setText(StringHelper.parseJson(s)); + + startCmdUdpServer(); + } + + @Override + public void onFailure(Exception e) { + + } + }); + } + + private void updateCurrentTimePerSecond() { + // 当前时间字体颜色为蓝色 + currentTimeLabel.setForeground(Color.BLUE); + + // 每秒更新 + new Timer(1000, e -> { + String systemTime = TimeOrDateUtil.timestampToTime(); + currentTimeLabel.setText(systemTime); + }).start(); + } + + private void startCmdUdpServer() { + EventLoopGroup workerGroup = new NioEventLoopGroup(); + try { + Bootstrap b = new Bootstrap();// + b.group(workerGroup).channel(NioDatagramChannel.class)//设置UDP通道 + .handler(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object o) throws Exception { + try { + DatagramPacket datagramPacket = (DatagramPacket) o; + String msg = datagramPacket.content().toString(CharsetUtil.UTF_8); + + if (msg.trim().toUpperCase().equals("SYNC")) { + updateView(); + } + } catch (Exception e) { + throw e; + } + } + })//初始化处理器 + .option(ChannelOption.SO_BROADCAST, true);// 支持广播 + + // 绑定端口,开始接收进来的连接 + ChannelFuture f = b.bind(Integer.parseInt(udpPortLabel.getText())).sync(); + + udpPortTitle.setText("监听端口[已监听]:"); + + //让线程进入wait状态,也就是main线程暂时不会执行到finally里面,nettyserver也持续运行,如果监听到关闭事件,可以优雅的关闭通道和nettyserver + f.channel().closeFuture().sync(); + } catch (Exception e) { + // TODO: handle exception + System.out.println("Exception:" + e.getMessage()); + workerGroup.shutdownGracefully(); + } + } } diff --git a/pom.xml b/pom.xml index 83b9dab..37c366a 100644 --- a/pom.xml +++ b/pom.xml @@ -33,5 +33,11 @@ okhttp 4.9.3 + + + io.netty + netty-all + 4.1.68.Final + \ No newline at end of file diff --git a/src/main/java/com/casic/swing/ui/TimeGuardNtp.form b/src/main/java/com/casic/swing/ui/TimeGuardNtp.form index ce81e35..3bf4535 100644 --- a/src/main/java/com/casic/swing/ui/TimeGuardNtp.form +++ b/src/main/java/com/casic/swing/ui/TimeGuardNtp.form @@ -44,7 +44,7 @@ - + @@ -55,7 +55,7 @@ - + @@ -87,20 +87,6 @@ - - - - - - - - - - - - - - @@ -133,7 +119,7 @@ - + @@ -153,7 +139,7 @@ - + @@ -163,7 +149,7 @@ - + @@ -173,7 +159,7 @@ - + @@ -181,6 +167,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/com/casic/swing/ui/TimeGuardNtp.java b/src/main/java/com/casic/swing/ui/TimeGuardNtp.java index 99913c8..aebd36e 100644 --- a/src/main/java/com/casic/swing/ui/TimeGuardNtp.java +++ b/src/main/java/com/casic/swing/ui/TimeGuardNtp.java @@ -4,6 +4,12 @@ import com.alibaba.fastjson.JSONObject; import com.casic.swing.utils.*; import com.google.common.util.concurrent.ThreadFactoryBuilder; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.DatagramPacket; +import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.util.CharsetUtil; import okhttp3.Request; import javax.swing.*; @@ -11,6 +17,7 @@ import java.net.InetAddress; import java.util.List; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -28,12 +35,16 @@ private JComboBox localHostBox; private JCheckBox autoCheckBox; private JButton updateTimeButton; + private JLabel udpPortLabel; + private JLabel udpPortTitle; - private final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor( - 1, new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build()); + private final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build()); + private ScheduledFuture future; private boolean hasNtp = false; private final String serverConfig; + private boolean isTaskRunning = false; + public static void main(String[] args) { new TimeGuardNtp(); } @@ -48,9 +59,9 @@ setLocationRelativeTo(null); setVisible(true); stateView.setText("未同步"); + recentlyTimeLabel.setText("无法确定最近同步时间"); setStateView(Color.GRAY); - ConfigHelper.saveConfig(); //检查环境 new SwingWorker() { @@ -71,35 +82,17 @@ } }.execute(); + // 获取后台地址的配置 serverConfig = ConfigHelper.getConfigData(); - /** - * 时间间隔,单位为毫秒 - * */ - currentTimeLabel.setForeground(Color.BLUE); - new Timer(1000, e -> { - String systemTime = TimeOrDateUtil.timestampToTime(); - currentTimeLabel.setText(systemTime); - }).start(); - String ntpTime = LogToFile.load(); - if (!"".equals(ntpTime)) { - recentlyTimeLabel.setText(ntpTime); - } else { - recentlyTimeLabel.setText("无法确定最近同步时间"); - } + // 每秒更新当前时间 + updateCurrentTimePerSecond(); - Request request = new Request.Builder().url(serverConfig + Constant.FREQUENCY_URL).build(); - HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { - @Override - public void onSuccess(String s) { - frequencyLabel.setText(StringHelper.parseJson(s)); - } + // 获取同步时间参数 + getParamTimeSync(); - @Override - public void onFailure(Exception e) { - - } - }); + // 获取监听的udp端口 + getParamCmdUdpPort(); //初始化JComboBox List addressList = HttpRequestHelper.localHost(); @@ -107,21 +100,28 @@ localHostBox.addItem(address.getHostAddress()); } + // 绑定自动同步复选框事件 autoCheckBox.addActionListener(e -> { JCheckBox checkBox = (JCheckBox) e.getSource(); if (checkBox.isSelected()) { updateTimeButton.setEnabled(false); hostTextField.setEnabled(false); - /** - * 开启同步,只能开启一个同步线程 - * - * scheduleAtFixedRate - * 是以上一个任务开始的时间计时,period时间过去后,检测上一个任务是否执行完毕 - * 如果上一个任务执行完毕,则当前任务立即执行 - * 如果上一个任务没有执行完毕,则需要等上一个任务执行完毕后立即执行 - * */ - executorService.scheduleAtFixedRate(this::updateView, 0, Integer.parseInt(frequencyLabel.getText()), TimeUnit.MINUTES); + + String host = hostTextField.getText().trim(); + if (host.isEmpty()) { + autoCheckBox.setSelected(false); + updateTimeButton.setEnabled(true); + hostTextField.setEnabled(true); + JOptionPane.showMessageDialog(ntpPanel, "授时中心服务器输入错误,请检查", "Runtime Error", JOptionPane.ERROR_MESSAGE); + return; + } + + // 立即执行一次任务 + future = executorService.schedule(this::updateView, 1, TimeUnit.SECONDS); } else { + if (null != future) { + future.cancel(true); + } updateTimeButton.setEnabled(true); hostTextField.setEnabled(true); } @@ -135,13 +135,29 @@ String host = hostTextField.getText().trim(); if (host.isEmpty()) { autoCheckBox.setSelected(false); + updateTimeButton.setEnabled(true); + hostTextField.setEnabled(true); JOptionPane.showMessageDialog(ntpPanel, "授时中心服务器输入错误,请检查", "Runtime Error", JOptionPane.ERROR_MESSAGE); return; } + + if (null != future) { + future.cancel(false); + } + + // 重新获取同步周期 + getParamTimeSync(); + // String result = CommandUtil.simulateNtpResult(); String result = CommandUtil.ntpDate(host); LogToFile.save(result); + // 重新启动定时任务 + if (autoCheckBox.isSelected() == true) { + future = executorService.schedule(this::updateView, Integer.parseInt(frequencyLabel.getText()) * 60 - 5, TimeUnit.SECONDS); + } + + // 向后台接口提交ntp同步校时的结果 JSONObject object = new JSONObject(); if ("".equals(result)) { setStateView(Color.RED); @@ -184,15 +200,14 @@ .post(HttpRequestHelper.createRequestBody(object.toJSONString())) .build(); HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { - @Override public void onSuccess(String s) { - + System.out.println("保存同步结果成功:" + object.get("deltaTime")); } @Override public void onFailure(Exception e) { - e.printStackTrace(); + System.out.println("保存同步结果失败:" + e.getMessage()); } }); } @@ -202,4 +217,83 @@ dotPanel.setPreferredSize(new Dimension(15, 15)); dotPanel.setBackground(color); } + + private void getParamTimeSync() { + Request request = new Request.Builder().url(serverConfig + Constant.FREQUENCY_URL).build(); + HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { + @Override + public void onSuccess(String s) { + frequencyLabel.setText(StringHelper.parseJson(s)); + } + + @Override + public void onFailure(Exception e) { + + } + }); + } + + private void getParamCmdUdpPort() { + Request request = new Request.Builder().url(serverConfig + Constant.CMD_UDP_PORT).build(); + HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { + @Override + public void onSuccess(String s) { + udpPortLabel.setText(StringHelper.parseJson(s)); + + startCmdUdpServer(); + } + + @Override + public void onFailure(Exception e) { + + } + }); + } + + private void updateCurrentTimePerSecond() { + // 当前时间字体颜色为蓝色 + currentTimeLabel.setForeground(Color.BLUE); + + // 每秒更新 + new Timer(1000, e -> { + String systemTime = TimeOrDateUtil.timestampToTime(); + currentTimeLabel.setText(systemTime); + }).start(); + } + + private void startCmdUdpServer() { + EventLoopGroup workerGroup = new NioEventLoopGroup(); + try { + Bootstrap b = new Bootstrap();// + b.group(workerGroup).channel(NioDatagramChannel.class)//设置UDP通道 + .handler(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object o) throws Exception { + try { + DatagramPacket datagramPacket = (DatagramPacket) o; + String msg = datagramPacket.content().toString(CharsetUtil.UTF_8); + + if (msg.trim().toUpperCase().equals("SYNC")) { + updateView(); + } + } catch (Exception e) { + throw e; + } + } + })//初始化处理器 + .option(ChannelOption.SO_BROADCAST, true);// 支持广播 + + // 绑定端口,开始接收进来的连接 + ChannelFuture f = b.bind(Integer.parseInt(udpPortLabel.getText())).sync(); + + udpPortTitle.setText("监听端口[已监听]:"); + + //让线程进入wait状态,也就是main线程暂时不会执行到finally里面,nettyserver也持续运行,如果监听到关闭事件,可以优雅的关闭通道和nettyserver + f.channel().closeFuture().sync(); + } catch (Exception e) { + // TODO: handle exception + System.out.println("Exception:" + e.getMessage()); + workerGroup.shutdownGracefully(); + } + } } diff --git a/src/main/java/com/casic/swing/utils/ConfigHelper.java b/src/main/java/com/casic/swing/utils/ConfigHelper.java index e7dbd11..d8e698f 100644 --- a/src/main/java/com/casic/swing/utils/ConfigHelper.java +++ b/src/main/java/com/casic/swing/utils/ConfigHelper.java @@ -6,57 +6,45 @@ * @author Administrator */ public class ConfigHelper { - public static void saveConfig() { - File rootDir = Constant.intRootDir(); - File configFile = new File(rootDir + File.separator + "config.txt"); - if (!configFile.exists()) { - try { - configFile.createNewFile(); - } catch (IOException e) { - e.printStackTrace(); - } + private static void saveConfig(File configFile) { + try { + FileWriter fileWriter = new FileWriter(configFile); + BufferedWriter writer = new BufferedWriter(fileWriter); + writer.write(Constant.DEFAULT_BASE_URL); + writer.flush(); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); } - if (0 == configFile.length() || !configFile.exists()) { - //写入配置文件 - try { - FileWriter fileWriter = new FileWriter(configFile); - BufferedWriter writer = new BufferedWriter(fileWriter); - writer.write("http://localhost:11410"); - writer.flush(); - writer.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - System.out.println("后台配置路径 ===> " + configFile.getAbsolutePath()); } public static String getConfigData() { + // 返回值 + StringBuilder data = new StringBuilder(); try { File rootDir = Constant.intRootDir(); File configFile = new File(rootDir + File.separator + "config.txt"); - if (!configFile.exists()) { - try { - configFile.createNewFile(); - } catch (IOException e) { - e.printStackTrace(); - } - } - InputStreamReader streamReader = new InputStreamReader(new FileInputStream(configFile)); - BufferedReader bufferedReader = new BufferedReader(streamReader); - StringBuilder data = new StringBuilder(); - String s; - try { + if (configFile.exists() == false) { + // 如果之前没有config file,则创建一个并写入默认值 + configFile.createNewFile(); + saveConfig(configFile); + + data.append(Constant.DEFAULT_BASE_URL); + } else { + InputStreamReader streamReader = new InputStreamReader(new FileInputStream(configFile)); + BufferedReader bufferedReader = new BufferedReader(streamReader); + + // 读取config文件中的内容 + String s; while ((s = bufferedReader.readLine()) != null) { - data.append(s); + data.append(s.trim()); } - return data.toString(); - } catch (IOException e) { - e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } - return ""; + finally { + return data.toString(); + } } } diff --git a/pom.xml b/pom.xml index 83b9dab..37c366a 100644 --- a/pom.xml +++ b/pom.xml @@ -33,5 +33,11 @@ okhttp 4.9.3 + + + io.netty + netty-all + 4.1.68.Final + \ No newline at end of file diff --git a/src/main/java/com/casic/swing/ui/TimeGuardNtp.form b/src/main/java/com/casic/swing/ui/TimeGuardNtp.form index ce81e35..3bf4535 100644 --- a/src/main/java/com/casic/swing/ui/TimeGuardNtp.form +++ b/src/main/java/com/casic/swing/ui/TimeGuardNtp.form @@ -44,7 +44,7 @@ - + @@ -55,7 +55,7 @@ - + @@ -87,20 +87,6 @@ - - - - - - - - - - - - - - @@ -133,7 +119,7 @@ - + @@ -153,7 +139,7 @@ - + @@ -163,7 +149,7 @@ - + @@ -173,7 +159,7 @@ - + @@ -181,6 +167,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/com/casic/swing/ui/TimeGuardNtp.java b/src/main/java/com/casic/swing/ui/TimeGuardNtp.java index 99913c8..aebd36e 100644 --- a/src/main/java/com/casic/swing/ui/TimeGuardNtp.java +++ b/src/main/java/com/casic/swing/ui/TimeGuardNtp.java @@ -4,6 +4,12 @@ import com.alibaba.fastjson.JSONObject; import com.casic.swing.utils.*; import com.google.common.util.concurrent.ThreadFactoryBuilder; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.DatagramPacket; +import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.util.CharsetUtil; import okhttp3.Request; import javax.swing.*; @@ -11,6 +17,7 @@ import java.net.InetAddress; import java.util.List; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -28,12 +35,16 @@ private JComboBox localHostBox; private JCheckBox autoCheckBox; private JButton updateTimeButton; + private JLabel udpPortLabel; + private JLabel udpPortTitle; - private final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor( - 1, new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build()); + private final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build()); + private ScheduledFuture future; private boolean hasNtp = false; private final String serverConfig; + private boolean isTaskRunning = false; + public static void main(String[] args) { new TimeGuardNtp(); } @@ -48,9 +59,9 @@ setLocationRelativeTo(null); setVisible(true); stateView.setText("未同步"); + recentlyTimeLabel.setText("无法确定最近同步时间"); setStateView(Color.GRAY); - ConfigHelper.saveConfig(); //检查环境 new SwingWorker() { @@ -71,35 +82,17 @@ } }.execute(); + // 获取后台地址的配置 serverConfig = ConfigHelper.getConfigData(); - /** - * 时间间隔,单位为毫秒 - * */ - currentTimeLabel.setForeground(Color.BLUE); - new Timer(1000, e -> { - String systemTime = TimeOrDateUtil.timestampToTime(); - currentTimeLabel.setText(systemTime); - }).start(); - String ntpTime = LogToFile.load(); - if (!"".equals(ntpTime)) { - recentlyTimeLabel.setText(ntpTime); - } else { - recentlyTimeLabel.setText("无法确定最近同步时间"); - } + // 每秒更新当前时间 + updateCurrentTimePerSecond(); - Request request = new Request.Builder().url(serverConfig + Constant.FREQUENCY_URL).build(); - HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { - @Override - public void onSuccess(String s) { - frequencyLabel.setText(StringHelper.parseJson(s)); - } + // 获取同步时间参数 + getParamTimeSync(); - @Override - public void onFailure(Exception e) { - - } - }); + // 获取监听的udp端口 + getParamCmdUdpPort(); //初始化JComboBox List addressList = HttpRequestHelper.localHost(); @@ -107,21 +100,28 @@ localHostBox.addItem(address.getHostAddress()); } + // 绑定自动同步复选框事件 autoCheckBox.addActionListener(e -> { JCheckBox checkBox = (JCheckBox) e.getSource(); if (checkBox.isSelected()) { updateTimeButton.setEnabled(false); hostTextField.setEnabled(false); - /** - * 开启同步,只能开启一个同步线程 - * - * scheduleAtFixedRate - * 是以上一个任务开始的时间计时,period时间过去后,检测上一个任务是否执行完毕 - * 如果上一个任务执行完毕,则当前任务立即执行 - * 如果上一个任务没有执行完毕,则需要等上一个任务执行完毕后立即执行 - * */ - executorService.scheduleAtFixedRate(this::updateView, 0, Integer.parseInt(frequencyLabel.getText()), TimeUnit.MINUTES); + + String host = hostTextField.getText().trim(); + if (host.isEmpty()) { + autoCheckBox.setSelected(false); + updateTimeButton.setEnabled(true); + hostTextField.setEnabled(true); + JOptionPane.showMessageDialog(ntpPanel, "授时中心服务器输入错误,请检查", "Runtime Error", JOptionPane.ERROR_MESSAGE); + return; + } + + // 立即执行一次任务 + future = executorService.schedule(this::updateView, 1, TimeUnit.SECONDS); } else { + if (null != future) { + future.cancel(true); + } updateTimeButton.setEnabled(true); hostTextField.setEnabled(true); } @@ -135,13 +135,29 @@ String host = hostTextField.getText().trim(); if (host.isEmpty()) { autoCheckBox.setSelected(false); + updateTimeButton.setEnabled(true); + hostTextField.setEnabled(true); JOptionPane.showMessageDialog(ntpPanel, "授时中心服务器输入错误,请检查", "Runtime Error", JOptionPane.ERROR_MESSAGE); return; } + + if (null != future) { + future.cancel(false); + } + + // 重新获取同步周期 + getParamTimeSync(); + // String result = CommandUtil.simulateNtpResult(); String result = CommandUtil.ntpDate(host); LogToFile.save(result); + // 重新启动定时任务 + if (autoCheckBox.isSelected() == true) { + future = executorService.schedule(this::updateView, Integer.parseInt(frequencyLabel.getText()) * 60 - 5, TimeUnit.SECONDS); + } + + // 向后台接口提交ntp同步校时的结果 JSONObject object = new JSONObject(); if ("".equals(result)) { setStateView(Color.RED); @@ -184,15 +200,14 @@ .post(HttpRequestHelper.createRequestBody(object.toJSONString())) .build(); HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { - @Override public void onSuccess(String s) { - + System.out.println("保存同步结果成功:" + object.get("deltaTime")); } @Override public void onFailure(Exception e) { - e.printStackTrace(); + System.out.println("保存同步结果失败:" + e.getMessage()); } }); } @@ -202,4 +217,83 @@ dotPanel.setPreferredSize(new Dimension(15, 15)); dotPanel.setBackground(color); } + + private void getParamTimeSync() { + Request request = new Request.Builder().url(serverConfig + Constant.FREQUENCY_URL).build(); + HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { + @Override + public void onSuccess(String s) { + frequencyLabel.setText(StringHelper.parseJson(s)); + } + + @Override + public void onFailure(Exception e) { + + } + }); + } + + private void getParamCmdUdpPort() { + Request request = new Request.Builder().url(serverConfig + Constant.CMD_UDP_PORT).build(); + HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { + @Override + public void onSuccess(String s) { + udpPortLabel.setText(StringHelper.parseJson(s)); + + startCmdUdpServer(); + } + + @Override + public void onFailure(Exception e) { + + } + }); + } + + private void updateCurrentTimePerSecond() { + // 当前时间字体颜色为蓝色 + currentTimeLabel.setForeground(Color.BLUE); + + // 每秒更新 + new Timer(1000, e -> { + String systemTime = TimeOrDateUtil.timestampToTime(); + currentTimeLabel.setText(systemTime); + }).start(); + } + + private void startCmdUdpServer() { + EventLoopGroup workerGroup = new NioEventLoopGroup(); + try { + Bootstrap b = new Bootstrap();// + b.group(workerGroup).channel(NioDatagramChannel.class)//设置UDP通道 + .handler(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object o) throws Exception { + try { + DatagramPacket datagramPacket = (DatagramPacket) o; + String msg = datagramPacket.content().toString(CharsetUtil.UTF_8); + + if (msg.trim().toUpperCase().equals("SYNC")) { + updateView(); + } + } catch (Exception e) { + throw e; + } + } + })//初始化处理器 + .option(ChannelOption.SO_BROADCAST, true);// 支持广播 + + // 绑定端口,开始接收进来的连接 + ChannelFuture f = b.bind(Integer.parseInt(udpPortLabel.getText())).sync(); + + udpPortTitle.setText("监听端口[已监听]:"); + + //让线程进入wait状态,也就是main线程暂时不会执行到finally里面,nettyserver也持续运行,如果监听到关闭事件,可以优雅的关闭通道和nettyserver + f.channel().closeFuture().sync(); + } catch (Exception e) { + // TODO: handle exception + System.out.println("Exception:" + e.getMessage()); + workerGroup.shutdownGracefully(); + } + } } diff --git a/src/main/java/com/casic/swing/utils/ConfigHelper.java b/src/main/java/com/casic/swing/utils/ConfigHelper.java index e7dbd11..d8e698f 100644 --- a/src/main/java/com/casic/swing/utils/ConfigHelper.java +++ b/src/main/java/com/casic/swing/utils/ConfigHelper.java @@ -6,57 +6,45 @@ * @author Administrator */ public class ConfigHelper { - public static void saveConfig() { - File rootDir = Constant.intRootDir(); - File configFile = new File(rootDir + File.separator + "config.txt"); - if (!configFile.exists()) { - try { - configFile.createNewFile(); - } catch (IOException e) { - e.printStackTrace(); - } + private static void saveConfig(File configFile) { + try { + FileWriter fileWriter = new FileWriter(configFile); + BufferedWriter writer = new BufferedWriter(fileWriter); + writer.write(Constant.DEFAULT_BASE_URL); + writer.flush(); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); } - if (0 == configFile.length() || !configFile.exists()) { - //写入配置文件 - try { - FileWriter fileWriter = new FileWriter(configFile); - BufferedWriter writer = new BufferedWriter(fileWriter); - writer.write("http://localhost:11410"); - writer.flush(); - writer.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - System.out.println("后台配置路径 ===> " + configFile.getAbsolutePath()); } public static String getConfigData() { + // 返回值 + StringBuilder data = new StringBuilder(); try { File rootDir = Constant.intRootDir(); File configFile = new File(rootDir + File.separator + "config.txt"); - if (!configFile.exists()) { - try { - configFile.createNewFile(); - } catch (IOException e) { - e.printStackTrace(); - } - } - InputStreamReader streamReader = new InputStreamReader(new FileInputStream(configFile)); - BufferedReader bufferedReader = new BufferedReader(streamReader); - StringBuilder data = new StringBuilder(); - String s; - try { + if (configFile.exists() == false) { + // 如果之前没有config file,则创建一个并写入默认值 + configFile.createNewFile(); + saveConfig(configFile); + + data.append(Constant.DEFAULT_BASE_URL); + } else { + InputStreamReader streamReader = new InputStreamReader(new FileInputStream(configFile)); + BufferedReader bufferedReader = new BufferedReader(streamReader); + + // 读取config文件中的内容 + String s; while ((s = bufferedReader.readLine()) != null) { - data.append(s); + data.append(s.trim()); } - return data.toString(); - } catch (IOException e) { - e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } - return ""; + finally { + return data.toString(); + } } } diff --git a/src/main/java/com/casic/swing/utils/Constant.java b/src/main/java/com/casic/swing/utils/Constant.java index 091f834..b9b076c 100644 --- a/src/main/java/com/casic/swing/utils/Constant.java +++ b/src/main/java/com/casic/swing/utils/Constant.java @@ -7,8 +7,11 @@ */ public class Constant { public static final String FREQUENCY_URL = "/config/findSingle?paraName=TIME_SYNC"; + public static final String CMD_UDP_PORT = "/config/findSingle?paraName=CMD_UDP_PORT"; public static final String SYNCHRONIZE_URL = "/ntp/saveResult"; + public static final String DEFAULT_BASE_URL = "http://111.198.10.15:11410"; + public static File intRootDir() { File rootDir = new File(System.getProperty("user.dir") + File.separator + "logs"); if (!rootDir.exists()) { diff --git a/pom.xml b/pom.xml index 83b9dab..37c366a 100644 --- a/pom.xml +++ b/pom.xml @@ -33,5 +33,11 @@ okhttp 4.9.3 + + + io.netty + netty-all + 4.1.68.Final + \ No newline at end of file diff --git a/src/main/java/com/casic/swing/ui/TimeGuardNtp.form b/src/main/java/com/casic/swing/ui/TimeGuardNtp.form index ce81e35..3bf4535 100644 --- a/src/main/java/com/casic/swing/ui/TimeGuardNtp.form +++ b/src/main/java/com/casic/swing/ui/TimeGuardNtp.form @@ -44,7 +44,7 @@ - + @@ -55,7 +55,7 @@ - + @@ -87,20 +87,6 @@ - - - - - - - - - - - - - - @@ -133,7 +119,7 @@ - + @@ -153,7 +139,7 @@ - + @@ -163,7 +149,7 @@ - + @@ -173,7 +159,7 @@ - + @@ -181,6 +167,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/com/casic/swing/ui/TimeGuardNtp.java b/src/main/java/com/casic/swing/ui/TimeGuardNtp.java index 99913c8..aebd36e 100644 --- a/src/main/java/com/casic/swing/ui/TimeGuardNtp.java +++ b/src/main/java/com/casic/swing/ui/TimeGuardNtp.java @@ -4,6 +4,12 @@ import com.alibaba.fastjson.JSONObject; import com.casic.swing.utils.*; import com.google.common.util.concurrent.ThreadFactoryBuilder; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.DatagramPacket; +import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.util.CharsetUtil; import okhttp3.Request; import javax.swing.*; @@ -11,6 +17,7 @@ import java.net.InetAddress; import java.util.List; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -28,12 +35,16 @@ private JComboBox localHostBox; private JCheckBox autoCheckBox; private JButton updateTimeButton; + private JLabel udpPortLabel; + private JLabel udpPortTitle; - private final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor( - 1, new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build()); + private final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build()); + private ScheduledFuture future; private boolean hasNtp = false; private final String serverConfig; + private boolean isTaskRunning = false; + public static void main(String[] args) { new TimeGuardNtp(); } @@ -48,9 +59,9 @@ setLocationRelativeTo(null); setVisible(true); stateView.setText("未同步"); + recentlyTimeLabel.setText("无法确定最近同步时间"); setStateView(Color.GRAY); - ConfigHelper.saveConfig(); //检查环境 new SwingWorker() { @@ -71,35 +82,17 @@ } }.execute(); + // 获取后台地址的配置 serverConfig = ConfigHelper.getConfigData(); - /** - * 时间间隔,单位为毫秒 - * */ - currentTimeLabel.setForeground(Color.BLUE); - new Timer(1000, e -> { - String systemTime = TimeOrDateUtil.timestampToTime(); - currentTimeLabel.setText(systemTime); - }).start(); - String ntpTime = LogToFile.load(); - if (!"".equals(ntpTime)) { - recentlyTimeLabel.setText(ntpTime); - } else { - recentlyTimeLabel.setText("无法确定最近同步时间"); - } + // 每秒更新当前时间 + updateCurrentTimePerSecond(); - Request request = new Request.Builder().url(serverConfig + Constant.FREQUENCY_URL).build(); - HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { - @Override - public void onSuccess(String s) { - frequencyLabel.setText(StringHelper.parseJson(s)); - } + // 获取同步时间参数 + getParamTimeSync(); - @Override - public void onFailure(Exception e) { - - } - }); + // 获取监听的udp端口 + getParamCmdUdpPort(); //初始化JComboBox List addressList = HttpRequestHelper.localHost(); @@ -107,21 +100,28 @@ localHostBox.addItem(address.getHostAddress()); } + // 绑定自动同步复选框事件 autoCheckBox.addActionListener(e -> { JCheckBox checkBox = (JCheckBox) e.getSource(); if (checkBox.isSelected()) { updateTimeButton.setEnabled(false); hostTextField.setEnabled(false); - /** - * 开启同步,只能开启一个同步线程 - * - * scheduleAtFixedRate - * 是以上一个任务开始的时间计时,period时间过去后,检测上一个任务是否执行完毕 - * 如果上一个任务执行完毕,则当前任务立即执行 - * 如果上一个任务没有执行完毕,则需要等上一个任务执行完毕后立即执行 - * */ - executorService.scheduleAtFixedRate(this::updateView, 0, Integer.parseInt(frequencyLabel.getText()), TimeUnit.MINUTES); + + String host = hostTextField.getText().trim(); + if (host.isEmpty()) { + autoCheckBox.setSelected(false); + updateTimeButton.setEnabled(true); + hostTextField.setEnabled(true); + JOptionPane.showMessageDialog(ntpPanel, "授时中心服务器输入错误,请检查", "Runtime Error", JOptionPane.ERROR_MESSAGE); + return; + } + + // 立即执行一次任务 + future = executorService.schedule(this::updateView, 1, TimeUnit.SECONDS); } else { + if (null != future) { + future.cancel(true); + } updateTimeButton.setEnabled(true); hostTextField.setEnabled(true); } @@ -135,13 +135,29 @@ String host = hostTextField.getText().trim(); if (host.isEmpty()) { autoCheckBox.setSelected(false); + updateTimeButton.setEnabled(true); + hostTextField.setEnabled(true); JOptionPane.showMessageDialog(ntpPanel, "授时中心服务器输入错误,请检查", "Runtime Error", JOptionPane.ERROR_MESSAGE); return; } + + if (null != future) { + future.cancel(false); + } + + // 重新获取同步周期 + getParamTimeSync(); + // String result = CommandUtil.simulateNtpResult(); String result = CommandUtil.ntpDate(host); LogToFile.save(result); + // 重新启动定时任务 + if (autoCheckBox.isSelected() == true) { + future = executorService.schedule(this::updateView, Integer.parseInt(frequencyLabel.getText()) * 60 - 5, TimeUnit.SECONDS); + } + + // 向后台接口提交ntp同步校时的结果 JSONObject object = new JSONObject(); if ("".equals(result)) { setStateView(Color.RED); @@ -184,15 +200,14 @@ .post(HttpRequestHelper.createRequestBody(object.toJSONString())) .build(); HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { - @Override public void onSuccess(String s) { - + System.out.println("保存同步结果成功:" + object.get("deltaTime")); } @Override public void onFailure(Exception e) { - e.printStackTrace(); + System.out.println("保存同步结果失败:" + e.getMessage()); } }); } @@ -202,4 +217,83 @@ dotPanel.setPreferredSize(new Dimension(15, 15)); dotPanel.setBackground(color); } + + private void getParamTimeSync() { + Request request = new Request.Builder().url(serverConfig + Constant.FREQUENCY_URL).build(); + HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { + @Override + public void onSuccess(String s) { + frequencyLabel.setText(StringHelper.parseJson(s)); + } + + @Override + public void onFailure(Exception e) { + + } + }); + } + + private void getParamCmdUdpPort() { + Request request = new Request.Builder().url(serverConfig + Constant.CMD_UDP_PORT).build(); + HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { + @Override + public void onSuccess(String s) { + udpPortLabel.setText(StringHelper.parseJson(s)); + + startCmdUdpServer(); + } + + @Override + public void onFailure(Exception e) { + + } + }); + } + + private void updateCurrentTimePerSecond() { + // 当前时间字体颜色为蓝色 + currentTimeLabel.setForeground(Color.BLUE); + + // 每秒更新 + new Timer(1000, e -> { + String systemTime = TimeOrDateUtil.timestampToTime(); + currentTimeLabel.setText(systemTime); + }).start(); + } + + private void startCmdUdpServer() { + EventLoopGroup workerGroup = new NioEventLoopGroup(); + try { + Bootstrap b = new Bootstrap();// + b.group(workerGroup).channel(NioDatagramChannel.class)//设置UDP通道 + .handler(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object o) throws Exception { + try { + DatagramPacket datagramPacket = (DatagramPacket) o; + String msg = datagramPacket.content().toString(CharsetUtil.UTF_8); + + if (msg.trim().toUpperCase().equals("SYNC")) { + updateView(); + } + } catch (Exception e) { + throw e; + } + } + })//初始化处理器 + .option(ChannelOption.SO_BROADCAST, true);// 支持广播 + + // 绑定端口,开始接收进来的连接 + ChannelFuture f = b.bind(Integer.parseInt(udpPortLabel.getText())).sync(); + + udpPortTitle.setText("监听端口[已监听]:"); + + //让线程进入wait状态,也就是main线程暂时不会执行到finally里面,nettyserver也持续运行,如果监听到关闭事件,可以优雅的关闭通道和nettyserver + f.channel().closeFuture().sync(); + } catch (Exception e) { + // TODO: handle exception + System.out.println("Exception:" + e.getMessage()); + workerGroup.shutdownGracefully(); + } + } } diff --git a/src/main/java/com/casic/swing/utils/ConfigHelper.java b/src/main/java/com/casic/swing/utils/ConfigHelper.java index e7dbd11..d8e698f 100644 --- a/src/main/java/com/casic/swing/utils/ConfigHelper.java +++ b/src/main/java/com/casic/swing/utils/ConfigHelper.java @@ -6,57 +6,45 @@ * @author Administrator */ public class ConfigHelper { - public static void saveConfig() { - File rootDir = Constant.intRootDir(); - File configFile = new File(rootDir + File.separator + "config.txt"); - if (!configFile.exists()) { - try { - configFile.createNewFile(); - } catch (IOException e) { - e.printStackTrace(); - } + private static void saveConfig(File configFile) { + try { + FileWriter fileWriter = new FileWriter(configFile); + BufferedWriter writer = new BufferedWriter(fileWriter); + writer.write(Constant.DEFAULT_BASE_URL); + writer.flush(); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); } - if (0 == configFile.length() || !configFile.exists()) { - //写入配置文件 - try { - FileWriter fileWriter = new FileWriter(configFile); - BufferedWriter writer = new BufferedWriter(fileWriter); - writer.write("http://localhost:11410"); - writer.flush(); - writer.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - System.out.println("后台配置路径 ===> " + configFile.getAbsolutePath()); } public static String getConfigData() { + // 返回值 + StringBuilder data = new StringBuilder(); try { File rootDir = Constant.intRootDir(); File configFile = new File(rootDir + File.separator + "config.txt"); - if (!configFile.exists()) { - try { - configFile.createNewFile(); - } catch (IOException e) { - e.printStackTrace(); - } - } - InputStreamReader streamReader = new InputStreamReader(new FileInputStream(configFile)); - BufferedReader bufferedReader = new BufferedReader(streamReader); - StringBuilder data = new StringBuilder(); - String s; - try { + if (configFile.exists() == false) { + // 如果之前没有config file,则创建一个并写入默认值 + configFile.createNewFile(); + saveConfig(configFile); + + data.append(Constant.DEFAULT_BASE_URL); + } else { + InputStreamReader streamReader = new InputStreamReader(new FileInputStream(configFile)); + BufferedReader bufferedReader = new BufferedReader(streamReader); + + // 读取config文件中的内容 + String s; while ((s = bufferedReader.readLine()) != null) { - data.append(s); + data.append(s.trim()); } - return data.toString(); - } catch (IOException e) { - e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } - return ""; + finally { + return data.toString(); + } } } diff --git a/src/main/java/com/casic/swing/utils/Constant.java b/src/main/java/com/casic/swing/utils/Constant.java index 091f834..b9b076c 100644 --- a/src/main/java/com/casic/swing/utils/Constant.java +++ b/src/main/java/com/casic/swing/utils/Constant.java @@ -7,8 +7,11 @@ */ public class Constant { public static final String FREQUENCY_URL = "/config/findSingle?paraName=TIME_SYNC"; + public static final String CMD_UDP_PORT = "/config/findSingle?paraName=CMD_UDP_PORT"; public static final String SYNCHRONIZE_URL = "/ntp/saveResult"; + public static final String DEFAULT_BASE_URL = "http://111.198.10.15:11410"; + public static File intRootDir() { File rootDir = new File(System.getProperty("user.dir") + File.separator + "logs"); if (!rootDir.exists()) { diff --git a/src/main/java/com/casic/swing/utils/HttpRequestHelper.java b/src/main/java/com/casic/swing/utils/HttpRequestHelper.java index 0c6c943..d355e6c 100644 --- a/src/main/java/com/casic/swing/utils/HttpRequestHelper.java +++ b/src/main/java/com/casic/swing/utils/HttpRequestHelper.java @@ -19,7 +19,7 @@ */ public class HttpRequestHelper { public static RequestBody createRequestBody(String value) { - return RequestBody.create(MediaType.parse("application/json; charset=utf-8"), value); + return RequestBody.Companion.create(value, MediaType.parse("application/json; charset=utf-8")); } public static void doHttpRequest(Request request, IHttpCallback httpCallback) { diff --git a/pom.xml b/pom.xml index 83b9dab..37c366a 100644 --- a/pom.xml +++ b/pom.xml @@ -33,5 +33,11 @@ okhttp 4.9.3 + + + io.netty + netty-all + 4.1.68.Final + \ No newline at end of file diff --git a/src/main/java/com/casic/swing/ui/TimeGuardNtp.form b/src/main/java/com/casic/swing/ui/TimeGuardNtp.form index ce81e35..3bf4535 100644 --- a/src/main/java/com/casic/swing/ui/TimeGuardNtp.form +++ b/src/main/java/com/casic/swing/ui/TimeGuardNtp.form @@ -44,7 +44,7 @@ - + @@ -55,7 +55,7 @@ - + @@ -87,20 +87,6 @@ - - - - - - - - - - - - - - @@ -133,7 +119,7 @@ - + @@ -153,7 +139,7 @@ - + @@ -163,7 +149,7 @@ - + @@ -173,7 +159,7 @@ - + @@ -181,6 +167,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/com/casic/swing/ui/TimeGuardNtp.java b/src/main/java/com/casic/swing/ui/TimeGuardNtp.java index 99913c8..aebd36e 100644 --- a/src/main/java/com/casic/swing/ui/TimeGuardNtp.java +++ b/src/main/java/com/casic/swing/ui/TimeGuardNtp.java @@ -4,6 +4,12 @@ import com.alibaba.fastjson.JSONObject; import com.casic.swing.utils.*; import com.google.common.util.concurrent.ThreadFactoryBuilder; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.DatagramPacket; +import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.util.CharsetUtil; import okhttp3.Request; import javax.swing.*; @@ -11,6 +17,7 @@ import java.net.InetAddress; import java.util.List; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -28,12 +35,16 @@ private JComboBox localHostBox; private JCheckBox autoCheckBox; private JButton updateTimeButton; + private JLabel udpPortLabel; + private JLabel udpPortTitle; - private final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor( - 1, new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build()); + private final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build()); + private ScheduledFuture future; private boolean hasNtp = false; private final String serverConfig; + private boolean isTaskRunning = false; + public static void main(String[] args) { new TimeGuardNtp(); } @@ -48,9 +59,9 @@ setLocationRelativeTo(null); setVisible(true); stateView.setText("未同步"); + recentlyTimeLabel.setText("无法确定最近同步时间"); setStateView(Color.GRAY); - ConfigHelper.saveConfig(); //检查环境 new SwingWorker() { @@ -71,35 +82,17 @@ } }.execute(); + // 获取后台地址的配置 serverConfig = ConfigHelper.getConfigData(); - /** - * 时间间隔,单位为毫秒 - * */ - currentTimeLabel.setForeground(Color.BLUE); - new Timer(1000, e -> { - String systemTime = TimeOrDateUtil.timestampToTime(); - currentTimeLabel.setText(systemTime); - }).start(); - String ntpTime = LogToFile.load(); - if (!"".equals(ntpTime)) { - recentlyTimeLabel.setText(ntpTime); - } else { - recentlyTimeLabel.setText("无法确定最近同步时间"); - } + // 每秒更新当前时间 + updateCurrentTimePerSecond(); - Request request = new Request.Builder().url(serverConfig + Constant.FREQUENCY_URL).build(); - HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { - @Override - public void onSuccess(String s) { - frequencyLabel.setText(StringHelper.parseJson(s)); - } + // 获取同步时间参数 + getParamTimeSync(); - @Override - public void onFailure(Exception e) { - - } - }); + // 获取监听的udp端口 + getParamCmdUdpPort(); //初始化JComboBox List addressList = HttpRequestHelper.localHost(); @@ -107,21 +100,28 @@ localHostBox.addItem(address.getHostAddress()); } + // 绑定自动同步复选框事件 autoCheckBox.addActionListener(e -> { JCheckBox checkBox = (JCheckBox) e.getSource(); if (checkBox.isSelected()) { updateTimeButton.setEnabled(false); hostTextField.setEnabled(false); - /** - * 开启同步,只能开启一个同步线程 - * - * scheduleAtFixedRate - * 是以上一个任务开始的时间计时,period时间过去后,检测上一个任务是否执行完毕 - * 如果上一个任务执行完毕,则当前任务立即执行 - * 如果上一个任务没有执行完毕,则需要等上一个任务执行完毕后立即执行 - * */ - executorService.scheduleAtFixedRate(this::updateView, 0, Integer.parseInt(frequencyLabel.getText()), TimeUnit.MINUTES); + + String host = hostTextField.getText().trim(); + if (host.isEmpty()) { + autoCheckBox.setSelected(false); + updateTimeButton.setEnabled(true); + hostTextField.setEnabled(true); + JOptionPane.showMessageDialog(ntpPanel, "授时中心服务器输入错误,请检查", "Runtime Error", JOptionPane.ERROR_MESSAGE); + return; + } + + // 立即执行一次任务 + future = executorService.schedule(this::updateView, 1, TimeUnit.SECONDS); } else { + if (null != future) { + future.cancel(true); + } updateTimeButton.setEnabled(true); hostTextField.setEnabled(true); } @@ -135,13 +135,29 @@ String host = hostTextField.getText().trim(); if (host.isEmpty()) { autoCheckBox.setSelected(false); + updateTimeButton.setEnabled(true); + hostTextField.setEnabled(true); JOptionPane.showMessageDialog(ntpPanel, "授时中心服务器输入错误,请检查", "Runtime Error", JOptionPane.ERROR_MESSAGE); return; } + + if (null != future) { + future.cancel(false); + } + + // 重新获取同步周期 + getParamTimeSync(); + // String result = CommandUtil.simulateNtpResult(); String result = CommandUtil.ntpDate(host); LogToFile.save(result); + // 重新启动定时任务 + if (autoCheckBox.isSelected() == true) { + future = executorService.schedule(this::updateView, Integer.parseInt(frequencyLabel.getText()) * 60 - 5, TimeUnit.SECONDS); + } + + // 向后台接口提交ntp同步校时的结果 JSONObject object = new JSONObject(); if ("".equals(result)) { setStateView(Color.RED); @@ -184,15 +200,14 @@ .post(HttpRequestHelper.createRequestBody(object.toJSONString())) .build(); HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { - @Override public void onSuccess(String s) { - + System.out.println("保存同步结果成功:" + object.get("deltaTime")); } @Override public void onFailure(Exception e) { - e.printStackTrace(); + System.out.println("保存同步结果失败:" + e.getMessage()); } }); } @@ -202,4 +217,83 @@ dotPanel.setPreferredSize(new Dimension(15, 15)); dotPanel.setBackground(color); } + + private void getParamTimeSync() { + Request request = new Request.Builder().url(serverConfig + Constant.FREQUENCY_URL).build(); + HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { + @Override + public void onSuccess(String s) { + frequencyLabel.setText(StringHelper.parseJson(s)); + } + + @Override + public void onFailure(Exception e) { + + } + }); + } + + private void getParamCmdUdpPort() { + Request request = new Request.Builder().url(serverConfig + Constant.CMD_UDP_PORT).build(); + HttpRequestHelper.doHttpRequest(request, new IHttpCallback() { + @Override + public void onSuccess(String s) { + udpPortLabel.setText(StringHelper.parseJson(s)); + + startCmdUdpServer(); + } + + @Override + public void onFailure(Exception e) { + + } + }); + } + + private void updateCurrentTimePerSecond() { + // 当前时间字体颜色为蓝色 + currentTimeLabel.setForeground(Color.BLUE); + + // 每秒更新 + new Timer(1000, e -> { + String systemTime = TimeOrDateUtil.timestampToTime(); + currentTimeLabel.setText(systemTime); + }).start(); + } + + private void startCmdUdpServer() { + EventLoopGroup workerGroup = new NioEventLoopGroup(); + try { + Bootstrap b = new Bootstrap();// + b.group(workerGroup).channel(NioDatagramChannel.class)//设置UDP通道 + .handler(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object o) throws Exception { + try { + DatagramPacket datagramPacket = (DatagramPacket) o; + String msg = datagramPacket.content().toString(CharsetUtil.UTF_8); + + if (msg.trim().toUpperCase().equals("SYNC")) { + updateView(); + } + } catch (Exception e) { + throw e; + } + } + })//初始化处理器 + .option(ChannelOption.SO_BROADCAST, true);// 支持广播 + + // 绑定端口,开始接收进来的连接 + ChannelFuture f = b.bind(Integer.parseInt(udpPortLabel.getText())).sync(); + + udpPortTitle.setText("监听端口[已监听]:"); + + //让线程进入wait状态,也就是main线程暂时不会执行到finally里面,nettyserver也持续运行,如果监听到关闭事件,可以优雅的关闭通道和nettyserver + f.channel().closeFuture().sync(); + } catch (Exception e) { + // TODO: handle exception + System.out.println("Exception:" + e.getMessage()); + workerGroup.shutdownGracefully(); + } + } } diff --git a/src/main/java/com/casic/swing/utils/ConfigHelper.java b/src/main/java/com/casic/swing/utils/ConfigHelper.java index e7dbd11..d8e698f 100644 --- a/src/main/java/com/casic/swing/utils/ConfigHelper.java +++ b/src/main/java/com/casic/swing/utils/ConfigHelper.java @@ -6,57 +6,45 @@ * @author Administrator */ public class ConfigHelper { - public static void saveConfig() { - File rootDir = Constant.intRootDir(); - File configFile = new File(rootDir + File.separator + "config.txt"); - if (!configFile.exists()) { - try { - configFile.createNewFile(); - } catch (IOException e) { - e.printStackTrace(); - } + private static void saveConfig(File configFile) { + try { + FileWriter fileWriter = new FileWriter(configFile); + BufferedWriter writer = new BufferedWriter(fileWriter); + writer.write(Constant.DEFAULT_BASE_URL); + writer.flush(); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); } - if (0 == configFile.length() || !configFile.exists()) { - //写入配置文件 - try { - FileWriter fileWriter = new FileWriter(configFile); - BufferedWriter writer = new BufferedWriter(fileWriter); - writer.write("http://localhost:11410"); - writer.flush(); - writer.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - System.out.println("后台配置路径 ===> " + configFile.getAbsolutePath()); } public static String getConfigData() { + // 返回值 + StringBuilder data = new StringBuilder(); try { File rootDir = Constant.intRootDir(); File configFile = new File(rootDir + File.separator + "config.txt"); - if (!configFile.exists()) { - try { - configFile.createNewFile(); - } catch (IOException e) { - e.printStackTrace(); - } - } - InputStreamReader streamReader = new InputStreamReader(new FileInputStream(configFile)); - BufferedReader bufferedReader = new BufferedReader(streamReader); - StringBuilder data = new StringBuilder(); - String s; - try { + if (configFile.exists() == false) { + // 如果之前没有config file,则创建一个并写入默认值 + configFile.createNewFile(); + saveConfig(configFile); + + data.append(Constant.DEFAULT_BASE_URL); + } else { + InputStreamReader streamReader = new InputStreamReader(new FileInputStream(configFile)); + BufferedReader bufferedReader = new BufferedReader(streamReader); + + // 读取config文件中的内容 + String s; while ((s = bufferedReader.readLine()) != null) { - data.append(s); + data.append(s.trim()); } - return data.toString(); - } catch (IOException e) { - e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } - return ""; + finally { + return data.toString(); + } } } diff --git a/src/main/java/com/casic/swing/utils/Constant.java b/src/main/java/com/casic/swing/utils/Constant.java index 091f834..b9b076c 100644 --- a/src/main/java/com/casic/swing/utils/Constant.java +++ b/src/main/java/com/casic/swing/utils/Constant.java @@ -7,8 +7,11 @@ */ public class Constant { public static final String FREQUENCY_URL = "/config/findSingle?paraName=TIME_SYNC"; + public static final String CMD_UDP_PORT = "/config/findSingle?paraName=CMD_UDP_PORT"; public static final String SYNCHRONIZE_URL = "/ntp/saveResult"; + public static final String DEFAULT_BASE_URL = "http://111.198.10.15:11410"; + public static File intRootDir() { File rootDir = new File(System.getProperty("user.dir") + File.separator + "logs"); if (!rootDir.exists()) { diff --git a/src/main/java/com/casic/swing/utils/HttpRequestHelper.java b/src/main/java/com/casic/swing/utils/HttpRequestHelper.java index 0c6c943..d355e6c 100644 --- a/src/main/java/com/casic/swing/utils/HttpRequestHelper.java +++ b/src/main/java/com/casic/swing/utils/HttpRequestHelper.java @@ -19,7 +19,7 @@ */ public class HttpRequestHelper { public static RequestBody createRequestBody(String value) { - return RequestBody.create(MediaType.parse("application/json; charset=utf-8"), value); + return RequestBody.Companion.create(value, MediaType.parse("application/json; charset=utf-8")); } public static void doHttpRequest(Request request, IHttpCallback httpCallback) { diff --git a/src/main/java/com/casic/swing/utils/LogToFile.java b/src/main/java/com/casic/swing/utils/LogToFile.java index d27cfd0..b050c5a 100644 --- a/src/main/java/com/casic/swing/utils/LogToFile.java +++ b/src/main/java/com/casic/swing/utils/LogToFile.java @@ -30,7 +30,7 @@ } OutputStreamWriter outStream = new OutputStreamWriter(fos, StandardCharsets.UTF_8); outStream.write(log); - outStream.write("\r\n"); +// outStream.write("\r\n"); //写入完成关闭流 outStream.close(); } catch (IOException e) { @@ -43,7 +43,7 @@ File rootDir = Constant.intRootDir(); File logFile = new File(rootDir + File.separator + DATE_FORMAT.format(new Date()) + "_ntp.log"); if (!logFile.exists()) { - logFile.createNewFile(); + // logFile.createNewFile(); return ""; } FileInputStream inputStream = new FileInputStream(logFile); @@ -59,14 +59,14 @@ return ""; } //取最后一条记录 - String[] content = data.toString().split("\r\n"); + String[] content = data.toString().trim().split("\r\n"); String result = content[content.length - 1]; /** * 5 Jan 11:20:24 ntpdate[807910]: adjust time server 114.118.7.161 offset -0.004064 sec * 5 Jan 11:24:06 ntpdate[824403]: no server suitable for synchronization found * */ String ntpDate = result.split("ntpdate")[0]; - String[] split = ntpDate.split(" "); + String[] split = ntpDate.trim().split(" "); Calendar date = Calendar.getInstance(); String year = String.valueOf(date.get(Calendar.YEAR));