tangle 2 سال پیش
والد
کامیت
d2e7c7158b
24فایلهای تغییر یافته به همراه2551 افزوده شده و 3 حذف شده
  1. 3 2
      pom.xml
  2. 48 0
      simulation-common/pom.xml
  3. 7 1
      simulation-receive/pom.xml
  4. 7 0
      simulation-receive/src/main/java/com/jiayue/simulation/ReceiveApplication.java
  5. 32 0
      simulation-receive/src/main/java/com/jiayue/simulation/config/ReceiveConfig.java
  6. 11 0
      simulation-receive/src/main/java/com/jiayue/simulation/entity/Channel102Client.java
  7. 12 0
      simulation-receive/src/main/java/com/jiayue/simulation/entity/Channel102Server.java
  8. 42 0
      simulation-receive/src/main/java/com/jiayue/simulation/entity/ChannelInfo.java
  9. 380 0
      simulation-receive/src/main/java/com/jiayue/simulation/enum/FileTypeEnum.java
  10. 48 0
      simulation-receive/src/main/java/com/jiayue/simulation/enum/ProvinceEnum.java
  11. 85 0
      simulation-receive/src/main/java/com/jiayue/simulation/ice102/Client.java
  12. 9 0
      simulation-receive/src/main/java/com/jiayue/simulation/ice102/ConsoleInterface.java
  13. 12 0
      simulation-receive/src/main/java/com/jiayue/simulation/ice102/Server.java
  14. 93 0
      simulation-receive/src/main/java/com/jiayue/simulation/ice102/codec/Decoder.java
  15. 21 0
      simulation-receive/src/main/java/com/jiayue/simulation/ice102/codec/Encoder.java
  16. 53 0
      simulation-receive/src/main/java/com/jiayue/simulation/ice102/handler/ClientHandler.java
  17. 27 0
      simulation-receive/src/main/java/com/jiayue/simulation/ice102/handler/ServerHandler.java
  18. 81 0
      simulation-receive/src/main/java/com/jiayue/simulation/ice102/service/ClientService.java
  19. 407 0
      simulation-receive/src/main/java/com/jiayue/simulation/util/ByteUtil.java
  20. 96 0
      simulation-receive/src/main/java/com/jiayue/simulation/util/IEC102Uitl.java
  21. 929 0
      simulation-receive/src/main/java/com/jiayue/simulation/util/RedisUtil.java
  22. 83 0
      simulation-receive/src/main/java/com/jiayue/simulation/util/SpringContextHolder.java
  23. 58 0
      simulation-receive/src/main/java/resources/mate-info/index.html
  24. 7 0
      simulation-send/pom.xml

+ 3 - 2
pom.xml

@@ -4,8 +4,9 @@
     <modelVersion>4.0.0</modelVersion>
     <packaging>pom</packaging>
     <modules>
-        <module>auxiliay-receive</module>
-        <module>auxiliay-send</module>
+        <module>simulation-receive</module>
+        <module>simulation-send</module>
+        <module>simulation-common</module>
     </modules>
     <parent>
         <groupId>org.springframework.boot</groupId>

+ 48 - 0
simulation-common/pom.xml

@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>simulation</artifactId>
+        <groupId>com.jiayue</groupId>
+        <version>0.0.1-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>simulation-conmmon</artifactId>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-all</artifactId>
+            <version>4.1.22.Final</version>
+        </dependency>
+        <dependency>
+            <groupId>redis.clients</groupId>
+            <artifactId>jedis</artifactId>
+            <version>3.2.0</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <mainClass>none</mainClass>     <!-- 取消查找本项目下的Main方法:为了解决Unable to find main class的问题 -->
+                    <classifier>execute</classifier>    <!-- 为了解决依赖模块找不到此模块中的类或属性 -->
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 7 - 1
simulation-receive/pom.xml

@@ -11,5 +11,11 @@
 
     <artifactId>simulation-receive</artifactId>
 
-
+    <dependencies>
+        <dependency>
+            <groupId>com.jiayue</groupId>
+            <artifactId>simulation-conmmon</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
 </project>

+ 7 - 0
simulation-receive/src/main/java/com/jiayue/simulation/ReceiveApplication.java

@@ -2,10 +2,17 @@ package com.jiayue.simulation;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
 
 @SpringBootApplication
 public class ReceiveApplication {
     public static void main(String[] args) {
         SpringApplication.run(ReceiveApplication.class);
     }
+
+
+    @Bean
+    void netty(){
+
+    }
 }

+ 32 - 0
simulation-receive/src/main/java/com/jiayue/simulation/config/ReceiveConfig.java

@@ -0,0 +1,32 @@
+package com.jiayue.simulation.config;
+
+import com.jiayue.simulation.ice102.Client;
+import com.jiayue.simulation.ice102.ConsoleInterface;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ReceiveConfig {
+
+
+    /**
+     * 暂时使用配置形式启动
+     * 想法:使用按钮选择启动各省份各类型的通信
+     */
+    @Bean
+    void start(){
+
+
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                new Client("192.168.1.77",3000);
+            }
+        }).start();
+
+        new Client("192.168.1.77",3000);
+
+    }
+
+}

+ 11 - 0
simulation-receive/src/main/java/com/jiayue/simulation/entity/Channel102Client.java

@@ -0,0 +1,11 @@
+package com.jiayue.simulation.entity;
+
+import lombok.Data;
+
+@Data
+public class Channel102Client {
+    /**
+     * 对端端口
+     */
+    private String inetPort;
+}

+ 12 - 0
simulation-receive/src/main/java/com/jiayue/simulation/entity/Channel102Server.java

@@ -0,0 +1,12 @@
+package com.jiayue.simulation.entity;
+
+import lombok.Data;
+
+@Data
+public class Channel102Server extends ChannelInfo {
+
+    /**
+     * 本地端口
+     */
+    private String localPort;
+}

+ 42 - 0
simulation-receive/src/main/java/com/jiayue/simulation/entity/ChannelInfo.java

@@ -0,0 +1,42 @@
+package com.jiayue.simulation.entity;
+
+public class ChannelInfo {
+
+    private Long id;
+
+    /**
+     * 本地ip
+     */
+    private String localHost;
+
+    /**
+     * 对端ip
+     */
+    private String inetHost;
+
+    /**
+     * 文件名称长度
+     */
+    private String fileNameLength;
+
+    /**
+     * 字节长度(单次接收字节)
+     */
+    private String byteLength;
+
+    /**
+     * 本地端口
+     */
+    private String localPort;
+
+    /**
+     * 所属省份
+     */
+    private String province;
+
+    /**
+     * 是否使用
+     */
+    private String isUse;
+
+}

+ 380 - 0
simulation-receive/src/main/java/com/jiayue/simulation/enum/FileTypeEnum.java

@@ -0,0 +1,380 @@
+package com.jiayue.simulation.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 文件类型枚举类
+ */
+@Getter
+@AllArgsConstructor
+public enum FileTypeEnum {
+	E1(1,"短期"),
+	E2(2,"超短期"),
+	E3(3,"理论功率"),
+	E4(4,"24NWP"),
+	E5(5,"72NWP"),
+	E6(6,"气象站"),
+	E7(7,"测风塔"),
+	E8(8,"逆变器"),
+	E9(9,"风机信息"),
+	E10(10,"光伏组件信息"),
+	E11(11,"检修计划"),
+	E12(12,"昨日开机容量"),
+	E13(13,"短期发电计划"),
+	E14(14,"超短期发电计划"),
+	E15(15,"日前预测"),
+	E16(16,"日前预测14"),
+	E17(17,"短期168"),
+	E18(18,"限电计划"),
+	E19(19,"弃电计划"),
+	E20(20,"场站信息"),
+	E21(21,"短期_集控"),
+	E22(22,"超短期_集控"),
+	E23(23,"测风塔_集控"),
+	E24(24,"72NWP_集控"),
+	E25(25,"短期_D5000"),
+	// 青海
+	E26(26,"可用短期"),
+	// 青海
+	E27(27,"可用超短期"),
+	// 宁夏
+	E28(28,"理论超短期"),
+	// 以下是青海新增
+	E29(29,"短期预测风速风向"),
+	E30(30,"实测功率"),
+	E31(31,"短期预测辐照度"),
+	E32(32,"短期日志"),
+	E33(33,"超短期日志"),
+	E34(34,"短期可用日志"),
+	E35(35,"超短期可用日志"),
+	E36(36,"气象站日志"),
+	E37(37,"理论功率日志"),
+	E38(38,"逆变器日志"),
+	E39(39,"风机信息日志"),
+	E40(40,"测风塔日志"),
+	E41(41,"指标数据"),
+	//贵州
+	E42(42,"电网上报状态"),
+	E43(43,"预测准确率"),
+	//海南
+	E44(44,"升压变"),
+	//青海
+	E45(45,"超短期预测风速风向"),
+	//广西
+	E46(46,"超短期SFTP"),
+	//青海
+	E47(47,"超短期预测辐照度"),
+	E48(48,"单机"),
+	//广西TODO
+	E49(49,"短期SFTP"),
+	//海南,广西(南方电网)
+	E50(50,"升压站信息"),
+	E51(51,"AGC_AVC信息"),
+	E52(52,"风电总体信息"),
+	E53(53,"光伏总体信息"),
+	E54(54,"统计信息"),
+	E55(55,"逆变器/汇流箱信息"),
+	E56(56,"南网短期预测"),
+	E57(57,"南网超短期预测"),
+	E58(58,"D5000样板机"),
+	E59(59,"短期02"),
+	E60(60,"离线理论功率"),
+	E61(61,"在线理论功率"),
+	//湖北康桥旧文件和湖北其他站的地调
+	E62(62,"湖北短期"),
+	E63(63,"湖北超短期"),
+	E64(64,"湖北72nwp"),
+	E65(65,"湖北气象站"),
+	E66(66,"湖北测风塔"),
+	E67(67,"湖北单机"),
+	//湖北康桥地调
+	E68(68,"荆门地调短期"),
+	E69(69,"荆门地调超短期"),
+	E70(70,"荆门地调72nwp"),
+	E71(71,"荆门地调气象站"),
+	E72(72,"荆门地调测风塔"),
+	E73(73,"荆门地调单机"),
+	E74(74,"荆门地调风机信息"),
+	E75(75,"荆门地调逆变器"),
+	E76(76,"南网风电机组"),
+	//新疆网调光伏
+	E77(77,"新疆网调逆变器"),
+	E78(78,"新疆网调气象站"),
+	E79(79,"新疆网调超短期"),
+	E80(80,"新疆网调短期"),
+	E81(81,"新疆网调实时量测"),
+	E82(82,"新疆网调集电线"),
+
+	E83(83,"南网压缩包"),
+	E84(84,"湖北逆变器"),
+	E85(85,"青海理论功率(风)"),
+	E86(86,"短期_辽宁龙源集控"),
+	E87(87,"超短期_辽宁龙源集控"),
+	E88(88,"测风塔_辽宁龙源集控"),
+	E89(89,"风机_辽宁龙源集控"),
+	//浙江省调上报文件
+	E90(90,"省调短期"),
+	E91(91,"省调昨日开机容量"),
+
+	E92(92,"湖北逆变器信息"),
+
+	E93(93,"黄冈地调短期"),
+	E94(94,"黄冈地调超短期"),
+	E95(95,"黄冈地调72nwp"),
+	E96(96,"黄冈地调气象站"),
+	E97(97,"黄冈地调测风塔"),
+	E98(98,"黄冈地调风机"),
+	E99(99,"黄冈地调逆变器"),
+
+	E100(100,"随州地调短期"),
+	E101(101,"随州地调超短期"),
+	E102(102,"随州地调72nwp"),
+	E103(103,"随州地调气象站"),
+	E104(104,"随州地调逆变器"),
+
+	E105(105,"广东中调短期WPD"),
+	E106(106,"广东中调超短期WPD"),
+	E107(107,"广东中调气象站WPD"),
+	E108(108,"广东中调逆变器WPD"),
+	E109(109,"广东中调短期dat"),
+	E110(110,"广东中调超短期dat"),
+	E111(111,"广东中调气象站dat"),
+	E112(112,"广东中调逆变器dat"),
+
+	E113(113,"NWP_辽宁龙源集控"),
+
+	E114(114,"蒙东南瑞集控测风塔"),
+	E115(115,"龙源南瑞集控测风塔"),
+
+	E116(116,"贵州总调短期"),
+	E117(117,"贵州总调超短期"),
+	E118(118,"贵州总调气象站"),
+	E119(119,"贵州总调逆变器"),
+
+	E120(120,"孝感地调测风塔"),
+	E121(121,"孝感地调风机"),
+
+	E122(122,"贵州新短期"),
+	E123(123,"贵州新超短期"),
+	E124(124,"贵州新气象站"),
+	E125(125,"贵州新测风塔"),
+	E126(126,"贵州新逆变器"),
+	E127(127,"贵州新风机"),
+	E128(128,"贵州新理论功率"),
+	E129(129,"贵州新逆变器信息"),
+	E130(130,"贵州新风机信息"),
+
+	E131(131,"山东新上午短期"),
+	E132(132,"山东新下午短期"),
+	E133(133,"山东新超短期"),
+	E134(134,"山东新气象站"),
+	E135(135,"山东新测风塔"),
+	E136(136,"山东新逆变器"),
+	E137(137,"山东新风机"),
+	E138(138,"山东新理论功率"),
+	E139(139,"山东新逆变器信息"),
+	E140(140,"山东新风机信息"),
+	E141(141,"孝感地调短期"),
+	E142(142,"孝感地调超短期"),
+	E143(143,"孝感地调nwp"),
+	E144(144,"日内预测短期"),
+	E145(145,"内蒙古新上午短期"),
+	E146(146,"内蒙古新下午短期"),
+	E147(147,"内蒙古新超短期"),
+
+	E148(148,"贵州中转短期"),
+	E149(149,"贵州中转超短期"),
+	E150(150,"贵州中转气象站"),
+	E151(151,"贵州中转统计信息"),
+	E152(152,"贵州中转方阵信息"),
+	E153(153,"甘肃新短期"),
+	E154(154,"甘肃12个月电量预测"),
+
+	E155(155,"吉林新上午短期"),
+	E156(156,"吉林新电量预测"),
+	E157(157,"吉林新下午短期"),
+
+	E158(158,"青海新电量预测"),
+	E159(159,"广西升压站信息"),
+	E160(160,"广西AGC-AVC信息"),
+	E161(161,"广西风电场总体信息"),
+	E162(162,"广西气象环境监视信息"),
+	E163(163,"广西风/光统计信息"),
+	E164(164,"广西逆变器/汇流箱信息"),
+	E165(165,"广西短期预测"),
+	E166(166,"广西超短期预测"),
+	E167(167,"广西风力发电机组信息"),
+	// 新疆用的短期下午
+	E168(168,"短期下午"),
+
+	E169(169,"河南漯河地调气象站"),
+	//江苏省调短期
+	E170(170,"省调短期"),
+	//江苏省调超短期
+	E171(171,"省调超短期"),
+	//江苏省调短期
+	E172(172,"省调旧短期"),
+	//江苏省调旧超短期
+	E173(173,"省调旧超短期"),
+
+
+	E174(174,"湖北咸宁地调短期"),
+	E175(175,"湖北咸宁地调超短期"),
+	E176(176,"湖北咸宁地调气象站"),
+	E177(177,"湖北咸宁地调逆变器"),
+	E178(178,"湖北咸宁地调NWP"),
+	E179(179,"湖北上午短期"),
+	E180(180,"湖北下午短期"),
+	E181(181,"湖北原短期下午"),
+
+	E182(182,"湖北上午短期(老系统)"),
+	E183(183,"湖北下午短期(老系统)"),
+	E184(184,"湖北原短期下午(老系统)"),
+
+	E185(185,"湖北荆州地调短期"),
+	E186(186,"湖北荆州地调超短期"),
+	E187(187,"湖北荆州地调nwp"),
+	E188(188,"湖北荆州地调测风塔"),
+	E189(189,"湖北荆州地调风机"),
+
+	E190(190,"江西萍乡地调短期"),
+	E191(191,"江西萍乡地调超短期"),
+	E192(192,"江西萍乡地调气象站"),
+
+	//黑龙江综合通信日志
+	E193(193,"72nwp日志(黑)"),
+	E194(194,"测风塔日志(黑)"),
+	E195(195,"风机日志(黑)"),
+	E196(196,"检修计划日志(黑)"),
+	E197(197,"短期日志(黑)"),
+	E198(198,"超短期日志(黑)"),
+	E199(199,"气象站日志(黑)"),
+	E200(200,"逆变器日志(黑)"),
+
+	E201(201,"黑龙江新电量预测"),
+
+	//华北直调
+	E202(202,"中短期功率预测"),
+
+	E203(203,"华北新可用超短期"),
+	E204(204,"华北新上午可用短期"),
+	E205(205,"华北新下午可用短期"),
+
+	E206(206,"冀北短期"),
+	E207(207,"冀北气象"),
+
+	E208(208,"(黑)三峡新能集控短期"),
+	E209(209,"(黑)三峡新能集控超短期"),
+	E210(210,"(黑)三峡新能集控nwp"),
+	E211(211,"(黑)三峡新能集控理论功率"),
+	E212(212,"(黑)三峡新能集控功率预测系统状态"),
+
+	E213(213,"广东升压站信息"),
+	E214(214,"广东AGC-AVC信息"),
+	E215(215,"广东风电场总体信息"),
+	E216(216,"广东气象环境监视信息"),
+	E217(217,"广东风/光统计信息"),
+	E218(218,"广东逆变器/汇流箱信息"),
+	E219(219,"广东短期预测"),
+	E220(220,"广东超短期预测"),
+	E221(221,"广东风力发电机组信息"),
+	E222(222,"广东箱变/方阵信息"),
+
+	E223(223,"辽宁三峡新能源短期"),
+	E224(224,"辽宁三峡新能源超短期"),
+
+	E225(225,"宜昌地调短期"),
+	E226(226,"宜昌地调超短期"),
+	E227(227,"宜昌地调NWP"),
+	E228(228,"宜昌地调测风塔"),
+	E229(229,"宜昌地调单机"),
+	E230(230,"宜昌地调气象站"),
+	E231(231,"宜昌地调逆变器"),
+	E232(232,"宜昌地调风机信息"),
+	E233(233,"宜昌地调逆变器信息"),
+
+	E234(234,"孝感地调气象站"),
+	E235(235,"孝感地调逆变器"),
+
+	E236(236,"开机容量(未来)"),
+
+	//湖北康桥地调
+	E237(237,"荆门地调72nwp(下午)"),
+	E238(238,"荆门地调短期(下午)"),
+
+	//河南地调文件
+	E239(239,"河南地调短期"),
+	E240(240,"河南地调超短期"),
+	E241(241,"河南地调24nwp"),
+	E242(242,"河南地调72nwp"),
+	E243(243,"河南地调测风塔"),
+	E244(244,"河南地调风机"),
+	E245(245,"河南地调昨日开机容量"),
+
+	E400(400,"新疆备调短期"),
+	E401(401,"新疆备调下午短期"),
+
+	E402(402,"单机转发上送"),
+
+	E500(500,"一体化短期"),
+	E501(501,"一体化短期(预测10天)");
+	/*
+	添加了超短期类型别忘了在下面getCDQ()方法中也加上
+	⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇
+	⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇
+	⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇
+	⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇
+	⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇
+	 */
+	private Integer code;
+	private String message;
+
+
+	//封装黑龙江类型的返回值
+	public static List<FileTypeEnum> getHLJ(){
+		List<FileTypeEnum> fileTypeEnums = new ArrayList<>();
+		fileTypeEnums.add(FileTypeEnum.E194);
+		fileTypeEnums.add(FileTypeEnum.E195);
+		fileTypeEnums.add(FileTypeEnum.E198);
+		fileTypeEnums.add(FileTypeEnum.E199);
+		fileTypeEnums.add(FileTypeEnum.E200);
+		return fileTypeEnums;
+	}
+
+
+	//封装所有使用超短期提前参数的超短期类型的返回值
+	public static List<FileTypeEnum> getCDQ(){
+		List<FileTypeEnum> fileTypeEnums = new ArrayList<>();
+		fileTypeEnums.add(FileTypeEnum.E2);
+		fileTypeEnums.add(FileTypeEnum.E27);
+		fileTypeEnums.add(FileTypeEnum.E63);
+		fileTypeEnums.add(FileTypeEnum.E69);
+		fileTypeEnums.add(FileTypeEnum.E79);
+		fileTypeEnums.add(FileTypeEnum.E94);
+		fileTypeEnums.add(FileTypeEnum.E101);
+		fileTypeEnums.add(FileTypeEnum.E106);
+		fileTypeEnums.add(FileTypeEnum.E110);
+		fileTypeEnums.add(FileTypeEnum.E117);
+		fileTypeEnums.add(FileTypeEnum.E123);
+		fileTypeEnums.add(FileTypeEnum.E133);
+		fileTypeEnums.add(FileTypeEnum.E147);
+		fileTypeEnums.add(FileTypeEnum.E149);
+		fileTypeEnums.add(FileTypeEnum.E166);
+		fileTypeEnums.add(FileTypeEnum.E171);
+		fileTypeEnums.add(FileTypeEnum.E173);
+		fileTypeEnums.add(FileTypeEnum.E175);
+		fileTypeEnums.add(FileTypeEnum.E186);
+		fileTypeEnums.add(FileTypeEnum.E191);
+		fileTypeEnums.add(FileTypeEnum.E203);
+		fileTypeEnums.add(FileTypeEnum.E220);
+		fileTypeEnums.add(FileTypeEnum.E224);
+		fileTypeEnums.add(FileTypeEnum.E226);
+		fileTypeEnums.add(FileTypeEnum.E240);
+		return fileTypeEnums;
+	}
+
+}

+ 48 - 0
simulation-receive/src/main/java/com/jiayue/simulation/enum/ProvinceEnum.java

@@ -0,0 +1,48 @@
+package com.jiayue.simulation.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 省调度中心枚举
+ */
+@Getter
+@AllArgsConstructor
+public enum ProvinceEnum {
+	E11(11, "北京市"),
+	E12(12, "天津市"),
+	E13(13, "河北省-冀北"),
+	E17(17, "河北省-南网"),
+	E14(14, "山西省"),
+	E15(15, "内蒙古自治区-蒙东"),
+	E16(16, "内蒙古自治区-蒙西"),
+	E21(21, "辽宁省"),
+	E22(22, "吉林省"),
+	E23(23, "黑龙江省"),
+	E31(31, "上海市"),
+	E32(32, "江苏省"),
+	E33(33, "浙江省"),
+	E34(34, "安徽省"),
+	E35(35, "福建省"),
+	E36(36, "江西省"),
+	E37(37, "山东省"),
+	E41(41, "河南省"),
+	E42(42, "湖北省"),
+	E43(43, "湖南省"),
+	E44(44, "广东省"),
+	E45(45, "广西壮族自治区"),
+	E46(46, "海南省"),
+	E50(50, "重庆市"),
+	E51(51, "四川省"),
+	E52(52, "贵州省"),
+	E53(53, "云南省"),
+	E54(54, "西藏自治区"),
+	E61(61, "陕西省"),
+	E62(62, "甘肃省"),
+	E63(63, "青海省"),
+	E64(64, "宁夏回族自治区"),
+	E65(65, "新疆维吾尔自治区"),
+	E99(99, "华北直调");
+	private Integer code;
+	private String message;
+}

+ 85 - 0
simulation-receive/src/main/java/com/jiayue/simulation/ice102/Client.java

@@ -0,0 +1,85 @@
+package com.jiayue.simulation.ice102;
+
+import com.jiayue.simulation.ice102.codec.Encoder;
+import com.jiayue.simulation.ice102.codec.Decoder;
+import com.jiayue.simulation.ice102.handler.ClientHandler;
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.timeout.IdleStateHandler;
+
+import java.util.concurrent.TimeUnit;
+
+public class Client implements ConsoleInterface {
+
+    private String ip;
+
+    private Integer port;
+
+
+    public Client(String ip,Integer port) {
+        this.ip = ip;
+        this.port = port;
+
+        start();
+    }
+
+    @Override
+    public void start() {
+        //客户端创建一个事件组
+        EventLoopGroup eventExecutors = new NioEventLoopGroup();
+
+        try {
+            //创建一个客户端启动对象
+            Bootstrap bootstrap = new Bootstrap();
+            bootstrap.group(eventExecutors)
+                    .channel(NioSocketChannel.class)
+                    .handler(new ChannelInitializer<SocketChannel>() {
+
+                        @Override
+                        protected void initChannel(SocketChannel socketChannel) throws Exception {
+                            socketChannel.pipeline().addLast(new IdleStateHandler(
+                                    60,
+                                    0,
+                                    0,
+                                    TimeUnit.SECONDS));
+                            //添加编解码
+                            socketChannel.pipeline().addLast("decoder", new Encoder());
+                            socketChannel.pipeline().addLast("encoder", new Decoder());
+                            socketChannel.pipeline().addLast(new ClientHandler());
+                        }
+                    });
+
+            //启动连接
+            ChannelFuture channelFuture = bootstrap.connect(ip, port);
+
+            channelFuture.addListener(new ChannelFutureListener() {
+                //使用匿名内部类,ChannelFutureListener接口
+                //重写operationComplete方法
+                @Override
+                public void operationComplete(ChannelFuture future) throws Exception {
+                    //判断是否操作成功
+                    if (future.isSuccess()) {
+                        System.out.println("客户端连接成功");
+                    } else {
+
+                        System.out.println("客户端连接失败");
+                    }
+                }
+            });
+
+            //监听关闭通道操作
+            channelFuture.channel().closeFuture().sync();
+
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+
+
+    }
+}

+ 9 - 0
simulation-receive/src/main/java/com/jiayue/simulation/ice102/ConsoleInterface.java

@@ -0,0 +1,9 @@
+package com.jiayue.simulation.ice102;
+
+/**
+ * 通道状态控制中心接口
+ */
+public interface ConsoleInterface {
+
+    void start();
+}

+ 12 - 0
simulation-receive/src/main/java/com/jiayue/simulation/ice102/Server.java

@@ -0,0 +1,12 @@
+package com.jiayue.simulation.ice102;
+
+/**
+ * 服务端
+ */
+public class Server implements ConsoleInterface {
+
+    @Override
+    public void start() {
+
+    }
+}

+ 93 - 0
simulation-receive/src/main/java/com/jiayue/simulation/ice102/codec/Decoder.java

@@ -0,0 +1,93 @@
+package com.jiayue.simulation.ice102.codec;
+
+import com.jiayue.simulation.util.ByteUtil;
+import com.jiayue.simulation.util.IEC102Uitl;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufUtil;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import lombok.extern.slf4j.Slf4j;
+
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 解码器
+ * @author tl
+ *
+ */
+@Slf4j
+public class Decoder extends SimpleChannelInboundHandler {
+    //记录上次未读完的字节
+    List<String> messageList = new ArrayList<String>();
+
+
+    @Override
+    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
+        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
+        // 获取远程IP
+        String remoteIP = insocket.getAddress().getHostAddress();
+        // 本地IP和端口
+        InetSocketAddress localAddress = (InetSocketAddress) ctx.channel().localAddress();
+        String localIp = localAddress.getAddress().getHostAddress();
+        String localPort = String.valueOf(localAddress.getPort());
+
+        try {
+            ByteBuf buf = (ByteBuf) msg;
+            String receiveStr = ByteBufUtil.hexDump(buf).toUpperCase();
+            List<String> receivesList = IEC102Uitl.stingToList(receiveStr);
+            messageList.addAll(receivesList);
+
+            // 至少6个以上字节才报文解码
+            if (messageList.size() >= 6) {
+//                if (messageList.size()>300){
+//                    // 没用的太多了,舍弃掉
+////                    uploadLogger.info("没用字符串报文超过300个舍弃掉:"+messageList.toString());
+//                    messageList.clear();
+//                }
+//                else{
+                    int zb = 0;
+                    while (true) {
+                        String nextMessage = "";
+                        for (int k = 0; k < messageList.size(); k++) {
+                            if ("10".equals(messageList.get(k)) && (k + 5) <= messageList.size() && messageList.get(k + 5).equals("16")) {
+                                List newList = messageList.subList(k, (k + 6));
+                                nextMessage = String.join("", newList);
+                                String tempStr = String.join("", messageList).substring((k + 6) * 2);
+                                messageList.clear();
+                                messageList = IEC102Uitl.stingToList(tempStr);
+                                break;
+                            }
+                            if ("68".equals(messageList.get(k)) && (k + 3) <= messageList.size() && messageList.get(k + 3).equals("68")) {
+                                int tempLength = ByteUtil.hexToDec(messageList.get(k + 2) + messageList.get(k + 1));
+                                int end16 = (k + 3) + tempLength + 2;
+                                if (end16 <= messageList.size() && messageList.get(end16).equals("16")) {
+                                    List newList = messageList.subList(k, (end16 + 1));
+                                    nextMessage = String.join("", newList);
+                                    String tempStr = String.join("", messageList).substring((end16 + 1) * 2);
+                                    messageList.clear();
+                                    messageList = IEC102Uitl.stingToList(tempStr);
+                                    break;
+                                }
+                            }
+                        }
+                        if (!"".equals(nextMessage)) {
+                            if (zb==1){
+//                                uploadLogger.info("获取到粘包帧:"+nextMessage);
+                            }
+                            zb++;
+                            ctx.fireChannelRead(nextMessage);
+                        }
+                        else {
+                            break;
+                        }
+                    }
+                }
+//            }
+        }
+        catch (Exception e){
+            log.error("解码失败",e);
+        }
+    }
+}

+ 21 - 0
simulation-receive/src/main/java/com/jiayue/simulation/ice102/codec/Encoder.java

@@ -0,0 +1,21 @@
+package com.jiayue.simulation.ice102.codec;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.MessageToByteEncoder;
+
+import java.math.BigInteger;
+
+/**
+ * 编码器
+ *
+ * @author tl
+ */
+public class Encoder extends MessageToByteEncoder<String> {
+    @Override
+    protected void encode(ChannelHandlerContext ctx, String msg, ByteBuf out) throws Exception {
+        BigInteger bigint = new BigInteger(msg, 16);
+        out.writeBytes(bigint.toByteArray());
+    }
+
+}

+ 53 - 0
simulation-receive/src/main/java/com/jiayue/simulation/ice102/handler/ClientHandler.java

@@ -0,0 +1,53 @@
+package com.jiayue.simulation.ice102.handler;
+
+import com.jiayue.simulation.ice102.service.ClientService;
+import com.jiayue.simulation.util.SpringContextHolder;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 服务端控制器
+ *
+ * @author tl
+ */
+@Slf4j
+public class ClientHandler extends ChannelInboundHandlerAdapter {
+
+
+
+    @Autowired
+    ClientService clientService = SpringContextHolder.getApplicationContext().getBean(ClientService.class);
+
+    //连接时触发
+    @Override
+    public void channelActive(ChannelHandlerContext ctx) throws Exception {
+
+        ctx.channel().writeAndFlush("1049FFFF4716");
+    }
+
+    //接收消息触发
+    @Override
+    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+
+        log.info("接收消息:{}",msg);
+        Thread.sleep(1000);
+        String s = clientService.sendMessage(msg.toString());
+        log.info("发送消息:{}",s);
+        ctx.channel().writeAndFlush(s);
+    }
+
+    //处理异常, 一般是需要关闭通道
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
+            throws Exception {
+        ctx.channel().close();
+    }
+
+    //客户端重连
+    @Override
+    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
+        super.channelInactive(ctx);
+    }
+}

+ 27 - 0
simulation-receive/src/main/java/com/jiayue/simulation/ice102/handler/ServerHandler.java

@@ -0,0 +1,27 @@
+package com.jiayue.simulation.ice102.handler;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+
+/**
+ * 服务端控制器
+ *
+ * @author tl
+ */
+public class ServerHandler extends ChannelInboundHandlerAdapter {
+
+    @Override
+    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+        super.channelRead(ctx, msg);
+    }
+
+    @Override
+    public void channelActive(ChannelHandlerContext ctx) throws Exception {
+        super.channelActive(ctx);
+    }
+
+    @Override
+    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
+        super.userEventTriggered(ctx, evt);
+    }
+}

+ 81 - 0
simulation-receive/src/main/java/com/jiayue/simulation/ice102/service/ClientService.java

@@ -0,0 +1,81 @@
+package com.jiayue.simulation.ice102.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jiayue.simulation.util.IEC102Uitl;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ClientService {
+
+    private String zh1 = "105AFFFF5916";
+    private String zh2 = "105BFFFF5916";
+
+    public String sendMessage(String receiveMessage){
+
+        String sendMessage = "";
+        String[] rmArray = IEC102Uitl.stingToArray(receiveMessage);
+
+        //召唤链路状态
+        if (rmArray.length==0) {
+            sendMessage = "1049FFFF4716";
+        }else if(receiveMessage.startsWith("100B")){
+            //链路状态回应请求->复位通信单元
+            sendMessage = "1040FFFF3E16";
+        }else if(receiveMessage.startsWith("1000")){
+            //确认帧->召唤二级数据
+            if(!zh2.equals("105BFFFF5916")){
+                sendMessage = "105BFFFF5916";
+            }else {
+                sendMessage = "105AFFFF5816";
+            }
+            zh2 = sendMessage;
+        }else if(receiveMessage.startsWith("1009")){
+            //没有召唤数据->召唤二级数据
+            if(!zh2.equals("105BFFFF5916")){
+                sendMessage = "105BFFFF5916";
+            }else {
+                sendMessage = "107BFFFF7916";
+            }
+            zh2 = sendMessage;
+        }else if(receiveMessage.startsWith("1029")){
+            //希望船速数据->召唤一级数据
+
+            if(!zh1.equals("107AFFFF7816")){
+                sendMessage = "107AFFFF7816";
+            }else {
+                sendMessage = "105AFFFF5816";
+            }
+            zh1 = sendMessage;
+        }else if(rmArray[9].equals("0B")){
+
+            if(!zh2.equals("105BFFFF5916")){
+                sendMessage = "105BFFFF5916";
+            }else {
+                sendMessage = "107BFFFF7916";
+            }
+            zh2 = sendMessage;
+        }else if(receiveMessage.startsWith("68")&&receiveMessage.endsWith("16")){
+            //68开头16结尾为数据船速;;希望传输数据->召唤一级数据
+
+            if(rmArray[9].equals("08")){
+                //文件传输未完成(还有内容)
+                if(!zh1.equals("107AFFFF7816")){
+                    sendMessage = "107AFFFF7816";
+                }else {
+                    sendMessage = "105AFFFF5816";
+                }
+                zh1 = sendMessage;
+            }else if (rmArray[9].equals("07")){
+                //文件传输结束
+                sendMessage = "680D006873FFFF96010AFFFF00CE4600002416";
+            }
+
+        }
+
+
+        return sendMessage.toUpperCase();
+
+    }
+}

+ 407 - 0
simulation-receive/src/main/java/com/jiayue/simulation/util/ByteUtil.java

@@ -0,0 +1,407 @@
+package com.jiayue.simulation.util;
+
+
+import com.sun.istack.internal.NotNull;
+import io.netty.buffer.ByteBuf;
+
+import javax.xml.bind.DatatypeConverter;
+import java.math.BigInteger;
+import java.util.Formatter;
+
+/**
+ * 字节转换工具类
+ */
+public abstract class ByteUtil {
+
+  /**
+   * int类型转换byte[4]数组,数组内字节由高到低
+   *
+   * @param n 被转换int
+   * @return byte[4]
+   */
+  public static byte[] intToBytesFromHighToLow(@NotNull int n) {
+    byte[] result = new byte[4];
+    result[0] = (byte) ((n >> 24) & 0xFF);
+    result[1] = (byte) ((n >> 16) & 0xFF);
+    result[2] = (byte) ((n >> 8) & 0xFF);
+    result[3] = (byte) (n & 0xFF);
+    return result;
+  }
+
+  /**
+   * byte[4]数组类型转换int,数组内字节由高到低
+   *
+   * @param b 被转换的字节数组
+   * @return int
+   */
+  public static int bytesToIntFromHighToLow(@NotNull byte[] b) {
+
+    return (b[(0)] & 0xFF) << 24 | (b[(1)] & 0xFF) << 16 |
+      (b[(2)] & 0xFF) << 8 | b[3] & 0xFF;
+  }
+
+
+  /**
+   * int类型转换byte[4]数组,数组内字节由低到高
+   *
+   * @param n 被转换int
+   * @return byte[4]
+   */
+  public static byte[] intToBytesFromLowToHigh(@NotNull int n) {
+    byte[] targets = new byte[4];
+
+    targets[0] = ((byte) (n & 0xFF));
+    targets[1] = ((byte) (n >> 8 & 0xFF));
+    targets[2] = ((byte) (n >> 16 & 0xFF));
+    targets[3] = ((byte) (n >> 24 & 0xFF));
+    return targets;
+  }
+
+  /**
+   * byte[4]数组类型转换int,数组内字节由低到高
+   *
+   * @param b 被转换的字节数组
+   * @return int
+   */
+  public static int bytesToIntFromLowToHigh(@NotNull byte[] b) {
+    return (b[(3)] & 0xFF) << 24 | (b[(2)] & 0xFF) << 16 |
+      (b[(1)] & 0xFF) << 8 | b[0] & 0xFF;
+  }
+
+  /**
+   * 二进制转十六进制,数组内字节由高到低
+   *
+   * @param b 二进制数组
+   * @return 十六进制字符串
+   */
+  public static String bytesToHexStringFromHighToLow(@NotNull byte[] b) {
+    return DatatypeConverter.printHexBinary(b);
+  }
+
+  /**
+   * 十六进制转二进制,数组内字节由高到低
+   *
+   * @param hexString 十六进制字符串
+   * @return 二进制数组
+   */
+  public static byte[] hexStringToBytesFromHighToLow(@NotNull String hexString) {
+    return DatatypeConverter.parseHexBinary(hexString);
+  }
+
+  /**
+   * 二进制转十六进制,数组内字节由低到高
+   *
+   * @param b 二进制数组
+   * @return 十六进制字符串
+   */
+  public static String bytesToHexStringFromLowToHigh(@NotNull byte[] b) {
+
+    byte[] dest = ByteUtil.bytesFlipping(b);
+    return DatatypeConverter.printHexBinary(dest);
+  }
+
+  /**
+   * 十六进制转二进制,数组内字节由低到高
+   *
+   * @param hexString 十六进制字符串
+   * @return 二进制数组
+   */
+  public static byte[] hexStringToBytesFromLowToHigh(@NotNull String hexString) {
+    byte[] dest = DatatypeConverter.parseHexBinary(hexString);
+    return ByteUtil.bytesFlipping(dest);
+  }
+
+  /**
+   * float转换byte[4]数组,数组内字节由低到高
+   *
+   * @param f 被转换float
+   * @return byte[4]
+   */
+  public static byte[] floatToBytesFromLowToHigh(@NotNull float f) {
+    int fbit = Float.floatToIntBits(f);
+
+    byte[] b = new byte[4];
+    for (int i = 0; i < 4; i++) {
+      b[i] = ((byte) (fbit >> 24 - i * 8));
+    }
+    // 翻转数组
+    return ByteUtil.bytesFlipping(b);
+  }
+
+  /**
+   * byte[4]数组转换float,数组内字节由低到高
+   *
+   * @param b 被转换字节数组
+   * @return float
+   */
+  public static float bytesToFloatFromLowToHigh(@NotNull byte[] b) {
+    int l = b[(0)];
+    l &= 255;
+    l = l | b[(1)] << 8;
+    l &= 65535;
+    l = l | b[(2)] << 16;
+    l &= 16777215;
+    l = l | b[(3)] << 24;
+    return Float.intBitsToFloat(l);
+  }
+
+  /**
+   * float转换byte[4]数组,数组内字节由高到低
+   *
+   * @param f 被转换float
+   * @return byte[4]
+   */
+  public static byte[] floatToBytesFromHighToLow(@NotNull float f) {
+    int fbit = Float.floatToIntBits(f);
+
+    byte[] b = new byte[4];
+    for (int i = 0; i < 4; i++) {
+      b[i] = ((byte) (fbit >> 24 - i * 8));
+    }
+    return b;
+  }
+
+  /**
+   * byte[4]数组转换float,数组内字节由高到低
+   *
+   * @param b 被转换字节数组
+   * @return float
+   */
+  public static float bytesToFloatFromHighToLow(@NotNull byte[] b) {
+    byte[] dest = ByteUtil.bytesFlipping(b);
+    return ByteUtil.bytesToFloatFromLowToHigh(dest);
+  }
+
+  /**
+   * 数组翻转
+   *
+   * @param res 原数组
+   * @return 翻转后的数组
+   */
+  public static byte[] bytesFlipping(@NotNull byte[] res) {
+    // 翻转数组
+    int len = res.length;
+    // 建立一个与源数组元素类型相同的数组
+    byte[] dest = new byte[len];
+    // 为了防止修改源数组,将源数组拷贝一份副本
+    System.arraycopy(res, 0, dest, 0, len);
+    // 将顺位第i个与倒数第i个交换
+    for (int i = 0; i < len / 2; i++) {
+      byte temp = dest[i];
+      dest[i] = dest[(len - i - 1)];
+      dest[(len - i - 1)] = temp;
+    }
+    return dest;
+  }
+
+  /**
+   * 强制转换字符串为字节数组
+   *
+   * @param s 字符串
+   * @return 字节数组
+   */
+  public static byte[] parseByte(String s) {
+    char[] c = s.toCharArray();
+    byte[] b = new byte[c.length];
+    for (int i = 0; i < c.length; i++) {
+      b[i] = Byte.parseByte(String.valueOf(c[i]));
+    }
+    return b;
+  }
+
+  /**
+   * 16进制转10进制
+   *
+   * @param hex 字符串
+   * @return int
+   */
+  public static int hexToDec(String hex) {
+    BigInteger bigint = new BigInteger(hex, 16);
+    return bigint.intValue();
+  }
+
+  /**
+   * 10进制转16进制字符串低位在前高位在后
+   *
+   * @param dec
+   * @return
+   */
+  public static String decToHex(int dec) {
+    int var1 = 1;
+    int var2 = dec >> 8;
+    int var3 = dec & 255;
+    String var4 = Integer.toHexString(var2);
+    String var5 = Integer.toHexString(var3);
+    if(var4.length() > 2) {
+      do {
+        if(var1 > 1) {
+          var2 >>= 8;
+        }
+        var4 = Integer.toHexString(var2 >> 8);
+        var5 = var5 + Integer.toHexString(var2 & 255);
+        ++var1;
+      } while(var4.length() > 2);
+    }
+    if(var4.length() < 2) {
+      var4 = "0" + var4;
+    }
+    if(var5.length() < 2) {
+      var5 = "0" + var5;
+    }
+    return var5 + var4;
+  }
+
+  /**
+   * 把byte[]数组转换成十六进制字符串表示形式
+   *
+   * @param tmp 要转换的byte[]
+   * @return 十六进制字符串表示形式
+   */
+  public static String byteToHexString(byte[] tmp) {
+    char hexdigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+    String s;
+    // 用字节表示就是 16 个字节
+    char str[] = new char[16 * 2]; // 每个字节用 16 进制表示的话,使用两个字符,
+    // 所以表示成 16 进制需要 32 个字符
+    int k = 0; // 表示转换结果中对应的字符位置
+    for (int i = 0; i < 16; i++) { // 从第一个字节开始,对 MD5 的每一个字节
+      // 转换成 16 进制字符的转换
+      byte byte0 = tmp[i]; // 取第 i 个字节
+      str[k++] = hexdigits[byte0 >>> 4 & 0xf]; // 取字节中高 4 位的数字转换,
+      // >>> 为逻辑右移,将符号位一起右移
+      str[k++] = hexdigits[byte0 & 0xf]; // 取字节中低 4 位的数字转换
+    }
+    s = new String(str); // 换后的结果转换为字符串
+    return s;
+  }
+
+  /**
+   * 16进制的字符串表示转成字节数组
+   *
+   * @param hexString
+   *            16进制格式的字符串
+   * @return 转换后的字节数组
+   **/
+  public static byte[] toByteArray(String hexString) {
+    final byte[] byteArray = new byte[hexString.length() / 2];
+    int k = 0;
+    for (int i = 0; i < byteArray.length; i++) {//因为是16进制,最多只会占用4位,转换成字节需要两个16进制的字符,高位在先
+      byte high = (byte) (Character.digit(hexString.charAt(k), 16) & 0xff);
+      byte low = (byte) (Character.digit(hexString.charAt(k + 1), 16) & 0xff);
+      byteArray[i] = (byte) (high << 4 | low);
+      k += 2;
+    }
+    return byteArray;
+  }
+
+  /**
+   * 字节数字转16进制字符串
+   *
+   * @param ba ba
+   * @return string
+   */
+  public static String Byte2String(byte[] ba){
+    if(ba == null || ba.length == 0)
+    { return null;}
+    Formatter f = new Formatter();
+    String resultStr;
+    try {
+      for (int i = 0; i < ba.length; ++i) {
+        f.format("%02x ", ba[i]);
+      }
+      resultStr = f.toString();
+    }
+    finally {
+      f.close();
+    }
+    return resultStr;
+  }
+
+  /**
+   * 字节数缓冲区字转16进制字符串
+   *
+   * @param buf buf
+   * @return string
+   */
+  public static String ByteBuf2String(ByteBuf buf){
+    if(!buf.isReadable()){
+      return null;
+    }
+    ByteBuf b1=buf.copy();
+    byte []bs=new byte[b1.readableBytes()];
+    b1.readBytes(bs);
+    b1.release();
+    return Byte2String(bs);
+  }
+
+  public static void main(String[] args) {
+    byte[] a = {89, 89, 71, 68, 52, 51, 95, 50, 48, 50, 49, 49, 48, 49, 56, 95, 49, 48, 49, 48, 95, 81, 88, 90, 46, 80, 86, 68};
+    String c= Byte2String(a);
+    System.out.println(c);
+//    byte[] b = {73,2};
+//    byte[] c = bytesFlipping(b);
+//    String info = DatatypeConverter.printHexBinary(c);
+//    BigInteger bigint=new BigInteger(info, 16);
+//    int numb=bigint.intValue();
+//    System.out.println(numb);
+
+//    String[] returnMessage = {"10", "ctrl", "FF", "FF", "crc", "16"};
+
+//    Long a=1589130920L;
+//    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+//    DataOutputStream dos = new DataOutputStream(baos);
+//    try {
+//      dos.writeLong(a);
+//    } catch (IOException e) {
+//      e.printStackTrace();
+//    }
+////再读出来
+//    byte[] buf = baos.toByteArray();
+//    System.out.println(bytesToHexStringFromHighToLow(intToBytesFromLowToHigh(bytesToIntFromHighToLow(buf))));
+//
+//
+//    System.out.println(bytesToHexStringFromHighToLow(floatToBytesFromLowToHigh(a.floatValue())));
+//
+//    System.out.println(bytesToHexStringFromHighToLow(intToBytesFromLowToHigh(a.intValue())));
+//
+//
+//
+//    System.out.println(bytesToHexStringFromHighToLow(intToBytesFromLowToHigh(hexToDec(Long.toHexString(a)))));
+
+//    System.out.println(bytesToIntFromLowToHigh(hexStringToBytesFromLowToHigh(Long.toHexString(a))));
+// A8 36 B8 5E
+//    byte[] b = {(byte)0x3c,(byte)0x00,(byte)0x00,(byte)0x00};
+//    System.out.println(a.intValue());
+
+
+//    int a=145;
+//    System.out.println(decToHex(183));
+//
+//    int var1 = 1;
+//    int var2 = 183 >> 8;
+//    int var3 = 183 & 255;
+//    String var4 = Integer.toHexString(var2);
+//    String var5 = Integer.toHexString(var3);
+//    if(var4.length() > 2) {
+//      do {
+//        if(var1 > 1) {
+//          var2 >>= 8;
+//        }
+//        var4 = Integer.toHexString(var2 >> 8);
+//        var5 = var5 + Integer.toHexString(var2 & 255);
+//        ++var1;
+//      } while(var4.length() > 2);
+//    }
+//    if(var4.length() < 2) {
+//      var4 = "0" + var4;
+//    }
+//    if(var5.length() < 2) {
+//      var5 = "0" + var5;
+//    }
+//    System.out.println(var5 + var4);
+
+
+//    int a=10;
+//    System.out.println(decToHex(a));
+  }
+}

+ 96 - 0
simulation-receive/src/main/java/com/jiayue/simulation/util/IEC102Uitl.java

@@ -0,0 +1,96 @@
+package com.jiayue.simulation.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 102工具类
+ */
+public class IEC102Uitl {
+  /**
+   * 取得是低位校验和
+   *
+   * @param data 需要计算校验和的16进制串
+   * @return 校验和
+   */
+  public static String makeChecksum(String data) {
+    int iTotal = 0;
+    int iLen = data.length();
+    int iNum = 0;
+
+    while (iNum < iLen) {
+      String s = data.substring(iNum, iNum + 2);
+      iTotal += Integer.parseInt(s, 16);
+      iNum = iNum + 2;
+    }
+
+    /**
+     * 用256求余最大是255,即16进制的FF
+     */
+    int iMod = iTotal % 256;
+    String sHex = Integer.toHexString(iMod);
+    iLen = sHex.length();
+    //如果不够校验位的长度,补0,这里用的是两位校验
+    if (iLen < 2) {
+      sHex = "0" + sHex;
+    }
+    return sHex;
+  }
+
+  /**
+   * 将字符串每2个放到一个数组中
+   *
+   * @param str
+   * @return
+   */
+  public static String[] stingToArray(String str) {
+    int m = str.length() / 2;
+    if (m * 2 < str.length()) {
+      m++;
+    }
+    String[] strs = new String[m];
+    int j = 0;
+    for (int i = 0; i < str.length(); i++) {
+      if (i % 2 == 0) {//每隔两zd个
+        strs[j] = "" + str.charAt(i);
+      } else {
+        strs[j] = strs[j] + str.charAt(i);//将字符加上两个空格
+        j++;
+      }
+    }
+    return strs;
+  }
+
+  /**
+   * 空格分割符字符串
+   * 每两位添加一个空格分隔符
+   *
+   * @param str str
+   * @return string
+   */
+  public static String delimiterStringBySpace(String str) {
+    if (str == null || "".equals(str.trim())) {
+      return null;
+    }
+    String regex = "(.{2})";
+    String result = str.replaceAll(regex, "$1 ");
+    return result;
+  }
+
+  public static List<String> stingToList(String str) {
+    List<String> list = new ArrayList<String>();
+    int m = str.length() / 2;
+    if (m * 2 < str.length()) {
+      m++;
+    }
+    int j = 0;
+    for (int i = 0; i < str.length(); i++) {
+      if (i % 2 == 0) {//每隔两zd个
+        list.add("" + str.charAt(i)+str.charAt(i+1));
+      } else {
+        j++;
+      }
+    }
+    return list;
+  }
+}

+ 929 - 0
simulation-receive/src/main/java/com/jiayue/simulation/util/RedisUtil.java

@@ -0,0 +1,929 @@
+package com.jiayue.simulation.util;
+
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.JedisPool;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author tengfei
+ * @version 1.0
+ * @date 2018/7/13 下午4:15
+ */
+public class RedisUtil {
+    private JedisPool pool = null;
+
+//    private RedisUtil() {
+//        if (pool == null) {
+//            String ip = SysConfigUtil.getSysConfigUtil("redis.properties").getString("redis.host");
+//            int port = SysConfigUtil.getSysConfigUtil("redis.properties").getInt("redis.port");
+//            String password = SysConfigUtil.getSysConfigUtil("redis.properties").getString("redis.password");
+//            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
+//            jedisPoolConfig.setMaxTotal(SysConfigUtil.getSysConfigUtil("redis.properties").getInt("redis.maxTotal"));
+//            jedisPoolConfig.setMaxIdle(SysConfigUtil.getSysConfigUtil("redis.properties").getInt("redis.maxIdle"));
+//            jedisPoolConfig.setMaxWaitMillis(SysConfigUtil.getSysConfigUtil("redis.properties").getLong("redis.maxWaitMillis"));
+//            jedisPoolConfig.setTestOnBorrow(SysConfigUtil.getSysConfigUtil("redis.properties").getBoolean("redis.testOnBorrow"));
+//            if (password != null && !"".equals(password)) {
+//                // redis 设置了密码
+//                pool = new JedisPool(jedisPoolConfig, ip, port, 10000, password);
+//            } else {
+//                // redis 未设置密码
+//                pool = new JedisPool(jedisPoolConfig, ip, port, 10000);
+//            }
+//        }
+//    }
+
+    /**
+     * 获取指定key的值,如果key不存在返回null,如果该Key存储的不是字符串,会抛出一个错误
+     *
+     * @param key
+     * @return
+     */
+    public String get(String key) {
+        Jedis jedis = getJedis();
+        String value = null;
+        value = jedis.get(key);
+        return value;
+    }
+
+    /**
+     * 设置key的值为value
+     *
+     * @param key
+     * @param value
+     * @return
+     */
+    public String set(String key, String value) {
+        Jedis jedis = getJedis();
+        return jedis.set(key, value);
+    }
+
+    /**
+     * 删除指定的key,也可以传入一个包含key的数组
+     *
+     * @param keys
+     * @return
+     */
+    public Long del(String... keys) {
+        Jedis jedis = getJedis();
+        return jedis.del(keys);
+    }
+
+    /**
+     * 通过key向指定的value值追加值
+     *
+     * @param key
+     * @param str
+     * @return
+     */
+    public Long append(String key, String str) {
+        Jedis jedis = getJedis();
+        return jedis.append(key, str);
+    }
+
+    /**
+     * 判断key是否存在
+     *
+     * @param key
+     * @return
+     */
+    public Boolean exists(String key) {
+        Jedis jedis = getJedis();
+        return jedis.exists(key);
+    }
+
+    /**
+     * 设置key value,如果key已经存在则返回0
+     *
+     * @param key
+     * @param value
+     * @return
+     */
+    public Long setnx(String key, String value) {
+        Jedis jedis = getJedis();
+        return jedis.setnx(key, value);
+    }
+
+    /**
+     * 设置key value并指定这个键值的有效期
+     *
+     * @param key
+     * @param seconds
+     * @param value
+     * @return
+     */
+    public String setex(String key, int seconds, String value) {
+        Jedis jedis = getJedis();
+        return jedis.setex(key, seconds, value);
+    }
+
+    /**
+     * 通过key 和offset 从指定的位置开始将原先value替换
+     *
+     * @param key
+     * @param offset
+     * @param str
+     * @return
+     */
+    public Long setrange(String key, int offset, String str) {
+        Jedis jedis = getJedis();
+        return jedis.setrange(key, offset, str);
+    }
+
+    /**
+     * 通过批量的key获取批量的value
+     *
+     * @param keys
+     * @return
+     */
+    public List<String> mget(String... keys) {
+        Jedis jedis = getJedis();
+        return jedis.mget(keys);
+    }
+
+    /**
+     * 批量的设置key:value,也可以一个
+     *
+     * @param keysValues
+     * @return
+     */
+    public String mset(String... keysValues) {
+        Jedis jedis = getJedis();
+        return jedis.mset(keysValues);
+    }
+
+    /**
+     * 批量的设置key:value,可以一个,如果key已经存在则会失败,操作会回滚
+     *
+     * @param keysValues
+     * @return
+     */
+    public Long msetnx(String... keysValues) {
+        Jedis jedis = getJedis();
+        return jedis.msetnx(keysValues);
+    }
+
+    /**
+     * 设置key的值,并返回一个旧值
+     *
+     * @param key
+     * @param value
+     * @return
+     */
+    public String getSet(String key, String value) {
+        Jedis jedis = getJedis();
+        return jedis.getSet(key, value);
+    }
+
+    /**
+     * 通过下标 和key 获取指定下标位置的 value
+     *
+     * @param key
+     * @param startOffset
+     * @param endOffset
+     * @return
+     */
+    public String getrange(String key, int startOffset, int endOffset) {
+        Jedis jedis = getJedis();
+        return jedis.getrange(key, startOffset, endOffset);
+    }
+
+    /**
+     * 通过key 对value进行加值+1操作,当value不是int类型时会返回错误,当key不存在是则value为1
+     *
+     * @param key
+     * @return
+     */
+    public Long incr(String key) {
+        Jedis jedis = getJedis();
+        return jedis.incr(key);
+    }
+
+    /**
+     * 通过key给指定的value加值,如果key不存在,则这是value为该值
+     *
+     * @param key
+     * @param integer
+     * @return
+     */
+    public Long incrBy(String key, long integer) {
+        Jedis jedis = getJedis();
+        return jedis.incrBy(key, integer);
+    }
+
+    /**
+     * 对key的值做减减操作,如果key不存在,则设置key为-1
+     *
+     * @param key
+     * @return
+     */
+    public Long decr(String key) {
+        Jedis jedis = getJedis();
+        return jedis.decr(key);
+    }
+
+    /**
+     * 减去指定的值
+     *
+     * @param key
+     * @param integer
+     * @return
+     */
+    public Long decrBy(String key, long integer) {
+        Jedis jedis = getJedis();
+        return jedis.decrBy(key, integer);
+    }
+
+    /**
+     * 通过key获取value值的长度
+     *
+     * @param key
+     * @return
+     */
+    public Long strLen(String key) {
+        Jedis jedis = getJedis();
+        return jedis.strlen(key);
+    }
+
+    /**
+     * 通过key给field设置指定的值,如果key不存在则先创建,如果field已经存在,返回0
+     *
+     * @param key
+     * @param field
+     * @param value
+     * @return
+     */
+    public Long hsetnx(String key, String field, String value) {
+        Jedis jedis = getJedis();
+        return jedis.hsetnx(key, field, value);
+    }
+
+    /**
+     * 通过key给field设置指定的值,如果key不存在,则先创建
+     *
+     * @param key
+     * @param field
+     * @param value
+     * @return
+     */
+    public Long hset(String key, String field, String value) {
+        Jedis jedis = getJedis();
+        return jedis.hset(key, field, value);
+    }
+
+    /**
+     * 通过key同时设置 hash的多个field
+     *
+     * @param key
+     * @param hash
+     * @return
+     */
+    public String hmset(String key, Map<String, String> hash) {
+        Jedis jedis = getJedis();
+        return jedis.hmset(key, hash);
+    }
+
+    /**
+     * 通过key 和 field 获取指定的 value
+     *
+     * @param key
+     * @param failed
+     * @return
+     */
+    public String hget(String key, String failed) {
+        Jedis jedis = getJedis();
+        return jedis.hget(key, failed);
+    }
+
+    /**
+     * 设置key的超时时间为seconds
+     *
+     * @param key
+     * @param seconds
+     * @return
+     */
+    public Long expire(String key, int seconds) {
+        Jedis jedis = getJedis();
+        return jedis.expire(key, seconds);
+    }
+
+    /**
+     * 通过key 和 fields 获取指定的value 如果没有对应的value则返回null
+     *
+     * @param key
+     * @param fields 可以是 一个String 也可以是 String数组
+     * @return
+     */
+    public List<String> hmget(String key, String... fields) {
+        Jedis jedis = getJedis();
+        return jedis.hmget(key, fields);
+    }
+
+    /**
+     * 通过key给指定的field的value加上给定的值
+     *
+     * @param key
+     * @param field
+     * @param value
+     * @return
+     */
+    public Long hincrby(String key, String field, Long value) {
+        Jedis jedis = getJedis();
+        return jedis.hincrBy(key, field, value);
+    }
+
+    /**
+     * 通过key和field判断是否有指定的value存在
+     *
+     * @param key
+     * @param field
+     * @return
+     */
+    public Boolean hexists(String key, String field) {
+        Jedis jedis = getJedis();
+        return jedis.hexists(key, field);
+    }
+
+    /**
+     * 通过key返回field的数量
+     *
+     * @param key
+     * @return
+     */
+    public Long hlen(String key) {
+        Jedis jedis = getJedis();
+        return jedis.hlen(key);
+    }
+
+    /**
+     * 通过key 删除指定的 field
+     *
+     * @param key
+     * @param fields 可以是 一个 field 也可以是 一个数组
+     * @return
+     */
+    public Long hdel(String key, String... fields) {
+        Jedis jedis = getJedis();
+        return jedis.hdel(key, fields);
+    }
+
+    /**
+     * 通过key返回所有的field
+     *
+     * @param key
+     * @return
+     */
+    public Set<String> hkeys(String key) {
+        Jedis jedis = getJedis();
+        return jedis.hkeys(key);
+    }
+
+    /**
+     * 通过key返回所有和key有关的value
+     *
+     * @param key
+     * @return
+     */
+    public List<String> hvals(String key) {
+        Jedis jedis = getJedis();
+        return jedis.hvals(key);
+    }
+
+    /**
+     * 通过key获取所有的field和value
+     *
+     * @param key
+     * @return
+     */
+    public Map<String, String> hgetall(String key) {
+        Jedis jedis = getJedis();
+        return jedis.hgetAll(key);
+    }
+
+    /**
+     * 通过key向list头部添加字符串
+     *
+     * @param key
+     * @param strs 可以是一个string 也可以是string数组
+     * @return 返回list的value个数
+     */
+    public Long lpush(String key, String... strs) {
+        Jedis jedis = getJedis();
+        return jedis.lpush(key, strs);
+    }
+
+    /**
+     * 通过key向list尾部添加字符串
+     *
+     * @param key
+     * @param strs 可以是一个string 也可以是string数组
+     * @return 返回list的value个数
+     */
+    public Long rpush(String key, String... strs) {
+        Jedis jedis = getJedis();
+        return jedis.rpush(key, strs);
+    }
+
+//    /**
+//     * 通过key在list指定的位置之前或者之后 添加字符串元素
+//     *
+//     * @param key
+//     * @param where LIST_POSITION枚举类型
+//     * @param pivot list里面的value
+//     * @param value 添加的value
+//     * @return
+//     */
+//    public Long linsert(String key, BinaryClient.LIST_POSITION where,
+//                        String pivot, String value) {
+//        Jedis jedis = getJedis();
+//        return jedis.linsert(key, where, pivot, value);
+//    }
+
+    /**
+     * 通过key设置list指定下标位置的value
+     * 如果下标超过list里面value的个数则报错
+     *
+     * @param key
+     * @param index 从0开始
+     * @param value
+     * @return 成功返回OK
+     */
+    public String lset(String key, Long index, String value) {
+        Jedis jedis = getJedis();
+        return jedis.lset(key, index, value);
+    }
+
+    /**
+     * 通过key从对应的list中删除指定的count个 和 value相同的元素
+     *
+     * @param key
+     * @param count 当count为0时删除全部
+     * @param value
+     * @return 返回被删除的个数
+     */
+    public Long lrem(String key, long count, String value) {
+        Jedis jedis = getJedis();
+        return jedis.lrem(key, count, value);
+    }
+
+    /**
+     * 通过key保留list中从strat下标开始到end下标结束的value值
+     *
+     * @param key
+     * @param start
+     * @param end
+     * @return 成功返回OK
+     */
+    public String ltrim(String key, long start, long end) {
+        Jedis jedis = getJedis();
+        return jedis.ltrim(key, start, end);
+    }
+
+    /**
+     * 通过key从list的头部删除一个value,并返回该value
+     *
+     * @param key
+     * @return
+     */
+    public synchronized String lpop(String key) {
+
+        Jedis jedis = getJedis();
+        return jedis.lpop(key);
+    }
+
+    /**
+     * 通过key从list尾部删除一个value,并返回该元素
+     *
+     * @param key
+     * @return
+     */
+    synchronized public String rpop(String key) {
+        Jedis jedis = getJedis();
+        return jedis.rpop(key);
+    }
+
+    /**
+     * 通过key从一个list的尾部删除一个value并添加到另一个list的头部,并返回该value
+     * 如果第一个list为空或者不存在则返回null
+     *
+     * @param srckey
+     * @param dstkey
+     * @return
+     */
+    public String rpoplpush(String srckey, String dstkey) {
+        Jedis jedis = getJedis();
+        return jedis.rpoplpush(srckey, dstkey);
+    }
+
+    /**
+     * 通过key获取list中指定下标位置的value
+     *
+     * @param key
+     * @param index
+     * @return 如果没有返回null
+     */
+    public String lindex(String key, long index) {
+        Jedis jedis = getJedis();
+        return jedis.lindex(key, index);
+    }
+
+    /**
+     * 通过key返回list的长度
+     *
+     * @param key
+     * @return
+     */
+    public Long llen(String key) {
+        Jedis jedis = getJedis();
+        return jedis.llen(key);
+    }
+
+    /**
+     * 通过key获取list指定下标位置的value
+     * 如果start 为 0 end 为 -1 则返回全部的list中的value
+     *
+     * @param key
+     * @param start
+     * @param end
+     * @return
+     */
+    public List<String> lrange(String key, long start, long end) {
+        Jedis jedis = getJedis();
+        return jedis.lrange(key, start, end);
+    }
+
+    /**
+     * 通过key向指定的set中添加value
+     *
+     * @param key
+     * @param members 可以是一个String 也可以是一个String数组
+     * @return 添加成功的个数
+     */
+    public Long sadd(String key, String... members) {
+        Jedis jedis = getJedis();
+        return jedis.sadd(key, members);
+    }
+
+    /**
+     * 通过key删除set中对应的value值
+     *
+     * @param key
+     * @param members 可以是一个String 也可以是一个String数组
+     * @return 删除的个数
+     */
+    public Long srem(String key, String... members) {
+        Jedis jedis = getJedis();
+        return jedis.srem(key, members);
+    }
+
+    /**
+     * 通过key随机删除一个set中的value并返回该值
+     *
+     * @param key
+     * @return
+     */
+    public String spop(String key) {
+        Jedis jedis = getJedis();
+        return jedis.spop(key);
+    }
+
+    /**
+     * 通过key获取set中的差集
+     * 以第一个set为标准
+     *
+     * @param keys 可以 是一个string 则返回set中所有的value 也可以是string数组
+     * @return
+     */
+    public Set<String> sdiff(String... keys) {
+        Jedis jedis = getJedis();
+        return jedis.sdiff(keys);
+    }
+
+    /**
+     * 通过key获取set中的差集并存入到另一个key中
+     * 以第一个set为标准
+     *
+     * @param dstkey 差集存入的key
+     * @param keys   可以 是一个string 则返回set中所有的value 也可以是string数组
+     * @return
+     */
+    public Long sdiffstore(String dstkey, String... keys) {
+        Jedis jedis = getJedis();
+        return jedis.sdiffstore(dstkey, keys);
+    }
+
+    /**
+     * 通过key获取指定set中的交集
+     *
+     * @param keys 可以 是一个string 也可以是一个string数组
+     * @return
+     */
+    public Set<String> sinter(String... keys) {
+        Jedis jedis = getJedis();
+        return jedis.sinter(keys);
+    }
+
+    /**
+     * 通过key获取指定set中的交集 并将结果存入新的set中
+     *
+     * @param dstkey
+     * @param keys   可以 是一个string 也可以是一个string数组
+     * @return
+     */
+    public Long sinterstore(String dstkey, String... keys) {
+        Jedis jedis = getJedis();
+        return jedis.sinterstore(dstkey, keys);
+    }
+
+    /**
+     * 通过key返回所有set的并集
+     *
+     * @param keys 可以 是一个string 也可以是一个string数组
+     * @return
+     */
+    public Set<String> sunion(String... keys) {
+        Jedis jedis = getJedis();
+        return jedis.sunion(keys);
+    }
+
+    /**
+     * 通过key返回所有set的并集,并存入到新的set中
+     *
+     * @param dstkey
+     * @param keys   可以 是一个string 也可以是一个string数组
+     * @return
+     */
+    public Long sunionstore(String dstkey, String... keys) {
+        Jedis jedis = getJedis();
+        return jedis.sunionstore(dstkey, keys);
+    }
+
+    /**
+     * 通过key将set中的value移除并添加到第二个set中
+     *
+     * @param srckey 需要移除的
+     * @param dstkey 添加的
+     * @param member set中的value
+     * @return
+     */
+    public Long smove(String srckey, String dstkey, String member) {
+        Jedis jedis = getJedis();
+        return jedis.smove(srckey, dstkey, member);
+    }
+
+    /**
+     * 通过key获取set中value的个数
+     *
+     * @param key
+     * @return
+     */
+    public Long scard(String key) {
+        Jedis jedis = getJedis();
+        return jedis.scard(key);
+    }
+
+    /**
+     * 通过key判断value是否是set中的元素
+     *
+     * @param key
+     * @param member
+     * @return
+     */
+    public Boolean sismember(String key, String member) {
+        Jedis jedis = getJedis();
+        return jedis.sismember(key, member);
+    }
+
+    /**
+     * 通过key获取set中随机的value,不删除元素
+     *
+     * @param key
+     * @return
+     */
+    public String srandmember(String key) {
+        Jedis jedis = getJedis();
+        return jedis.srandmember(key);
+    }
+
+    /**
+     * 通过key获取set中所有的value
+     *
+     * @param key
+     * @return
+     */
+    public Set<String> smembers(String key) {
+        Jedis jedis = getJedis();
+        return jedis.smembers(key);
+    }
+
+
+    /**
+     * 通过key向zset中添加value,score,其中score就是用来排序的
+     * 如果该value已经存在则根据score更新元素
+     *
+     * @param key
+     * @param score
+     * @param member
+     * @return
+     */
+    public Long zadd(String key, double score, String member) {
+        Jedis jedis = getJedis();
+        return jedis.zadd(key, score, member);
+    }
+
+    /**
+     * 通过key删除在zset中指定的value
+     *
+     * @param key
+     * @param members 可以 是一个string 也可以是一个string数组
+     * @return
+     */
+    public Long zrem(String key, String... members) {
+        Jedis jedis = getJedis();
+        return jedis.zrem(key, members);
+    }
+
+    /**
+     * 通过key增加该zset中value的score的值
+     *
+     * @param key
+     * @param score
+     * @param member
+     * @return
+     */
+    public Double zincrby(String key, double score, String member) {
+        Jedis jedis = getJedis();
+        return jedis.zincrby(key, score, member);
+    }
+
+    /**
+     * 通过key返回zset中value的排名
+     * 下标从小到大排序
+     *
+     * @param key
+     * @param member
+     * @return
+     */
+    public Long zrank(String key, String member) {
+        Jedis jedis = getJedis();
+        return jedis.zrank(key, member);
+    }
+
+    /**
+     * 通过key返回zset中value的排名
+     * 下标从大到小排序
+     *
+     * @param key
+     * @param member
+     * @return
+     */
+    public Long zrevrank(String key, String member) {
+        Jedis jedis = getJedis();
+        return jedis.zrevrank(key, member);
+    }
+
+    /**
+     * 通过key将获取score从start到end中zset的value
+     * socre从大到小排序
+     * 当start为0 end为-1时返回全部
+     *
+     * @param key
+     * @param start
+     * @param end
+     * @return
+     */
+    public Set<String> zrevrange(String key, long start, long end) {
+        Jedis jedis = getJedis();
+        return jedis.zrevrange(key, start, end);
+    }
+
+    /**
+     * 通过key返回指定score内zset中的value
+     *
+     * @param key
+     * @param max
+     * @param min
+     * @return
+     */
+    public Set<String> zrangebyscore(String key, String max, String min) {
+        Jedis jedis = getJedis();
+        return jedis.zrevrangeByScore(key, max, min);
+    }
+
+    /**
+     * 通过key返回指定score内zset中的value
+     *
+     * @param key
+     * @param max
+     * @param min
+     * @return
+     */
+    public Set<String> zrangeByScore(String key, double max, double min) {
+        Jedis jedis = getJedis();
+        return jedis.zrevrangeByScore(key, max, min);
+    }
+
+    /**
+     * 返回指定区间内zset中value的数量
+     *
+     * @param key
+     * @param min
+     * @param max
+     * @return
+     */
+    public Long zcount(String key, String min, String max) {
+        Jedis jedis = getJedis();
+        return jedis.zcount(key, min, max);
+    }
+
+    /**
+     * 通过key返回zset中的value个数
+     *
+     * @param key
+     * @return
+     */
+    public Long zcard(String key) {
+        Jedis jedis = getJedis();
+        return jedis.zcard(key);
+    }
+
+    /**
+     * 通过key获取zset中value的score值
+     *
+     * @param key
+     * @param member
+     * @return
+     */
+    public Double zscore(String key, String member) {
+        Jedis jedis = getJedis();
+        return jedis.zscore(key, member);
+    }
+
+    /**
+     * 通过key删除给定区间内的元素
+     *
+     * @param key
+     * @param start
+     * @param end
+     * @return
+     */
+    public Long zremrangeByRank(String key, long start, long end) {
+        Jedis jedis = getJedis();
+        return jedis.zremrangeByRank(key, start, end);
+    }
+
+    /**
+     * 通过key删除指定score内的元素
+     *
+     * @param key
+     * @param start
+     * @param end
+     * @return
+     */
+    public Long zremrangeByScore(String key, double start, double end) {
+        Jedis jedis = getJedis();
+        return jedis.zremrangeByScore(key, start, end);
+    }
+
+    /**
+     * 返回满足pattern表达式的所有key
+     * keys(*)
+     * 返回所有的key
+     *
+     * @param pattern
+     * @return
+     */
+    public Set<String> keys(String pattern) {
+        Jedis jedis = getJedis();
+        return jedis.keys(pattern);
+    }
+
+    /**
+     * 通过key判断值得类型
+     *
+     * @param key
+     * @return
+     */
+    public String type(String key) {
+        Jedis jedis = getJedis();
+        return jedis.type(key);
+    }
+
+
+    private void close(Jedis jedis) {
+        if (jedis != null) {
+            jedis.close();
+        }
+    }
+
+    private Jedis getJedis() {
+        return pool.getResource();
+    }
+
+    public static RedisUtil getRedisUtil() {
+        return new RedisUtil();
+    }
+
+}

+ 83 - 0
simulation-receive/src/main/java/com/jiayue/simulation/util/SpringContextHolder.java

@@ -0,0 +1,83 @@
+package com.jiayue.simulation.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author
+ * @date 2018/6/27
+ * Spring 工具类
+ */
+@Slf4j
+@Service
+@Lazy(false)
+public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
+
+    private static ApplicationContext applicationContext = null;
+
+    /**
+     * 取得存储在静态变量中的ApplicationContext.
+     */
+    public static ApplicationContext getApplicationContext() {
+        return applicationContext;
+    }
+
+    /**
+     * 实现ApplicationContextAware接口, 注入Context到静态变量中.
+     */
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) {
+        SpringContextHolder.applicationContext = applicationContext;
+    }
+
+    /**
+     * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getBean(String name) {
+        return (T) applicationContext.getBean(name);
+    }
+
+    /**
+     * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
+     */
+    public static <T> T getBean(Class<T> requiredType) {
+        return applicationContext.getBean(requiredType);
+    }
+
+    /**
+     * 清除SpringContextHolder中的ApplicationContext为Null.
+     */
+    public static void clearHolder() {
+        if (log.isDebugEnabled()) {
+            log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
+        }
+        applicationContext = null;
+    }
+
+    /**
+     * 发布事件
+     *
+     * @param event
+     */
+    public static void publishEvent(ApplicationEvent event) {
+        if (applicationContext == null) {
+            return;
+        }
+        applicationContext.publishEvent(event);
+    }
+
+    /**
+     * 实现DisposableBean接口, 在Context关闭时清理静态变量.
+     */
+    @Override
+    public void destroy() {
+        SpringContextHolder.clearHolder();
+    }
+
+}

+ 58 - 0
simulation-receive/src/main/java/resources/mate-info/index.html

@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Title</title>
+</head>
+<body>
+<form onsubmit="return false">
+    <p>输入文本</p>
+    <textarea id="message" name="message" style="height: 300px; width: 300px"></textarea>
+    <input type="button" value="发送消息" onclick="send(this.form.message.value)">
+
+    <p>回复文本</p>
+    <textarea id="responseText" style="height: 300px; width: 300px"></textarea>
+    <input type="button" value="清空内容" onclick="document.getElementById('responseText').value=''">
+</form>
+</body>
+<script>
+    var socket;
+    // 判断当前浏览器是否支持 WebSocket
+    if (window.WebSocket){
+        socket = new WebSocket("ws://localhost:8000/hello");
+        // 相当于 channelRead0 方法,ev 收到服务器端回送的消息
+        socket.onmessage = function (ev){
+            var rt = document.getElementById("responseText");
+            rt.value = rt.value + "\n" + ev.data;
+        }
+        // 相当于连接开启,感知到连接开启
+        socket.onopen = function (){
+            var rt = document.getElementById("responseText");
+            rt.value = rt.value + "\n" + "连接开启……";
+        }
+        // 感知连接关闭
+        socket.onclose = function (){
+            var rt = document.getElementById("responseText");
+            rt.value = rt.value + "\n" + "连接关闭……";
+        }
+    }else {
+        alert("不支持 WebSocket");
+    }
+
+    // 发送消息到服务器
+    function send(message){
+        // 判断 WebSocket 是否创建好了
+        if (!window.socket){
+            return ;
+        }
+        // 判断 WebSocket 是否开启
+        if (socket.readyState == WebSocket.OPEN){
+            // 通过 Socket 发送消息
+            socket.send(message);
+        }else {
+            alert("连接未开启");
+        }
+    }
+</script>
+
+</html>

+ 7 - 0
simulation-send/pom.xml

@@ -11,5 +11,12 @@
 
     <artifactId>simulation-send</artifactId>
 
+    <dependencies>
+        <dependency>
+            <groupId>com.jiayue</groupId>
+            <artifactId>simulation-conmmon</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
 
 </project>