S7 更新了一个大版本,待测试
This commit is contained in:
		
							
								
								
									
										14
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								pom.xml
									
									
									
									
									
								
							| @@ -80,11 +80,19 @@ | ||||
|         </dependency> | ||||
|         <!-- websocket                                                 结束 --> | ||||
|  | ||||
|         <!-- retry                                                 结束 --> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework.retry</groupId> | ||||
|             <artifactId>spring-retry</artifactId> | ||||
|             <version>1.2.2.RELEASE</version> | ||||
|         </dependency> | ||||
|         <!-- retry                                                 结束 --> | ||||
|  | ||||
|         <!-- fastjson                                                 开始 --> | ||||
|         <dependency> | ||||
|             <groupId>com.alibaba</groupId> | ||||
|             <artifactId>fastjson</artifactId> | ||||
|             <version>1.2.78</version> | ||||
|             <version>2.0.21</version> | ||||
|         </dependency> | ||||
|         <!-- fastjson                                                 结束 --> | ||||
|         <!-- hutool                                                 开始 --> | ||||
| @@ -201,6 +209,10 @@ | ||||
|             <artifactId>influxdb-client-java</artifactId> | ||||
|             <version>6.7.0</version> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>junit</groupId> | ||||
|             <artifactId>junit</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- influx end --> | ||||
|  | ||||
|   | ||||
| @@ -30,7 +30,7 @@ public interface S7Connector extends Closeable { | ||||
| 	 * @param offset | ||||
| 	 * @return | ||||
| 	 */ | ||||
| 	public byte[] read(DaveArea area, int areaNumber, int bytes, int offset) throws Exception; | ||||
| 	public byte[] read(DaveArea area, int areaNumber, int bytes, int offset); | ||||
|  | ||||
| 	/** | ||||
| 	 * Reads an area  读需要bit 位置的 变量(其实就是 read bool变量的时候调用这个方法。) | ||||
| @@ -41,7 +41,7 @@ public interface S7Connector extends Closeable { | ||||
| 	 * @param offset | ||||
| 	 * @return | ||||
| 	 */ | ||||
| 	public byte[] read(DaveArea area, int areaNumber, int bytes, int offset, int bitOffset, TransportSize transportSize) throws Exception; | ||||
| 	public byte[] read(DaveArea area, int areaNumber, int bytes, int offset, int bitOffset, TransportSize transportSize); | ||||
| 	/** | ||||
| 	 * Writes an area | ||||
| 	 * desc : 只要未抛出异常,都是 操作成功的 | ||||
| @@ -50,9 +50,9 @@ public interface S7Connector extends Closeable { | ||||
| 	 * @param offset | ||||
| 	 * @param buffer | ||||
| 	 */ | ||||
| 	public void write(DaveArea area, int areaNumber, int offset, byte[] buffer) throws Exception; | ||||
| 	public void write(DaveArea area, int areaNumber, int offset, byte[] buffer); | ||||
|  | ||||
| 	//如果 bitOffset 没有  那么就填0 | ||||
| 	public void write(DaveArea area, int areaNumber, int byteOffset, int bitOffset, byte[] buffer, PlcVar var) throws Exception; | ||||
| 	public void write(DaveArea area, int areaNumber, int byteOffset, int bitOffset, byte[] buffer, PlcVar var); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -6,6 +6,7 @@ package com.qgs.dc.s7.my.s7connector.api.utils; | ||||
|  * @DATE: 2021/12/16 9:08 | ||||
|  */ | ||||
|  | ||||
| import com.qgs.dc.s7.my.s7connector.exception.S7ParseDataException; | ||||
| import com.qgs.dc.s7.my.s7connector.utils.CommonFunctions; | ||||
|  | ||||
| import java.io.UnsupportedEncodingException; | ||||
| @@ -47,9 +48,14 @@ public class ByteUtils { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static String addDate(String timeParam, Long day) throws ParseException { | ||||
|     public static String addDate(String timeParam, Long day) { | ||||
|         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); // 日期格式 | ||||
|         Date date = dateFormat.parse(timeParam); // 指定日期 | ||||
|         Date date = null; | ||||
|         try { | ||||
|             date = dateFormat.parse(timeParam); // 指定日期 | ||||
|         }catch (Exception e){ | ||||
|             throw new S7ParseDataException("ByteUtils.addDate error:", e); | ||||
|         } | ||||
|  | ||||
|         long time = date.getTime(); // 得到指定日期的毫秒数 | ||||
|         day = day * 24 * 60 * 60 * 1000; // 要加上的天数转换成毫秒数 | ||||
| @@ -175,13 +181,13 @@ public class ByteUtils { | ||||
| //        String ascii = new String(b, Charset.forName("UTF-8")); | ||||
| //        return ascii; | ||||
| //    } | ||||
|     public static Character toChar(byte[] b) throws UnsupportedEncodingException { | ||||
|     public static Character toChar(byte[] b)  { | ||||
|         if(b.length==1){ | ||||
|             return toChar(b[0]); | ||||
|         } | ||||
|         return byteToChar(b); | ||||
|     } | ||||
|     public static Character toChar(byte b) throws UnsupportedEncodingException { | ||||
|     public static Character toChar(byte b){ | ||||
|         return byteToChar(b); | ||||
|     } | ||||
| //    public static String toChar(byte b) throws UnsupportedEncodingException { | ||||
| @@ -194,7 +200,7 @@ public class ByteUtils { | ||||
|     /** | ||||
|      * return null 代表返回传入参数不正确str 取的length太小 | ||||
|      * */ | ||||
|     public static String toStr(byte[] b) throws UnsupportedEncodingException { | ||||
|     public static String toStr(byte[] b) { | ||||
|         Integer length = Byte.toUnsignedInt(b[1]); | ||||
|         if(length>(b.length-2)){ | ||||
|             return null; | ||||
| @@ -207,7 +213,7 @@ public class ByteUtils { | ||||
|        // String s = new String(content); | ||||
|         return ascii; | ||||
|     } | ||||
|     public static String[] toStrArray(byte[] b,Integer length,Integer strSize) throws UnsupportedEncodingException { | ||||
|     public static String[] toStrArray(byte[] b,Integer length,Integer strSize) { | ||||
|         String[] res = new String[length]; | ||||
|         strSize+=2; | ||||
|         for(int i=0;i<length;i++){ | ||||
| @@ -275,7 +281,7 @@ public class ByteUtils { | ||||
|         return b; | ||||
|     } | ||||
|  | ||||
|     public static List<Boolean> toBoolArray(byte[] b) throws UnsupportedEncodingException { | ||||
|     public static List<Boolean> toBoolArray(byte[] b) { | ||||
|         List<Boolean> res = new ArrayList<>(); | ||||
|         for(int i=0;i<b.length;i++){ | ||||
|             boolean[] booleanArray = getBooleanArray(b[i], true); | ||||
| @@ -301,7 +307,7 @@ public class ByteUtils { | ||||
|  | ||||
|  | ||||
|     //bool array to byte array | ||||
|     public static byte[] toByteArray(boolean[] b) throws UnsupportedEncodingException { | ||||
|     public static byte[] toByteArray(boolean[] b){ | ||||
|         Integer byteLength = CommonFunctions.exactDivision(b.length, 8); | ||||
|         byte[] res = new byte[byteLength]; | ||||
|         Queue<Boolean> queue = new LinkedList<Boolean>(); | ||||
| @@ -347,7 +353,7 @@ public class ByteUtils { | ||||
| //        return res; | ||||
| //    } | ||||
|  | ||||
|     public static List<Byte> toByteArray(byte[] b) throws UnsupportedEncodingException { | ||||
|     public static List<Byte> toByteArray(byte[] b) { | ||||
|         List<Byte> res = new ArrayList<>(); | ||||
|         for(int i=0;i<b.length;i++){ | ||||
|             res.add((b[i])); | ||||
| @@ -355,7 +361,7 @@ public class ByteUtils { | ||||
|         return res; | ||||
|     } | ||||
|  | ||||
|     public static List<Character> toCharArray(byte[] b) throws UnsupportedEncodingException { | ||||
|     public static List<Character> toCharArray(byte[] b) { | ||||
|         List<Character> res = new ArrayList<>(); | ||||
|         for(int i=0;i<b.length;i++){ | ||||
|             res.add(toChar(b[i])); | ||||
| @@ -367,7 +373,7 @@ public class ByteUtils { | ||||
|     /** | ||||
|      * 默认:word => 有符号的整形 | ||||
|      * */ | ||||
|     public static List<Integer> toWordArray(byte[] b) throws UnsupportedEncodingException { | ||||
|     public static List<Integer> toWordArray(byte[] b) { | ||||
|         List<Integer> res = new ArrayList<>(); | ||||
|         int i=0; | ||||
|         while ((i+2)<=b.length){ | ||||
| @@ -383,7 +389,7 @@ public class ByteUtils { | ||||
|     /** | ||||
|      * 默认:dword => 有符号的整形 | ||||
|      * */ | ||||
|     public static List<Integer> toDWordArray(byte[] b) throws UnsupportedEncodingException { | ||||
|     public static List<Integer> toDWordArray(byte[] b) { | ||||
|         List<Integer> res = new ArrayList<>(); | ||||
|         int i=0; | ||||
|         while ((i+4)<=b.length){ | ||||
| @@ -444,7 +450,7 @@ public class ByteUtils { | ||||
|     /** | ||||
|      * USInt 无符号整形 1个字节  =》 Integer | ||||
|      * */ | ||||
|     public static List<Integer> toUSIntArray(byte[] b) throws UnsupportedEncodingException { | ||||
|     public static List<Integer> toUSIntArray(byte[] b) { | ||||
|         List<Integer> res = new ArrayList<>(); | ||||
|         for(int i=0;i<b.length;i++){ | ||||
|             res.add(toUInt(b[i])); | ||||
| @@ -454,7 +460,7 @@ public class ByteUtils { | ||||
|     /** | ||||
|      * UInt 无符号整形 2个字节  =》 Integer | ||||
|      * */ | ||||
|     public static List<Integer> toUIntArray(byte[] b) throws UnsupportedEncodingException { | ||||
|     public static List<Integer> toUIntArray(byte[] b) { | ||||
|         List<Integer> res = new ArrayList<>(); | ||||
|         int i=0; | ||||
|         while ((i+2)<=b.length){ | ||||
| @@ -468,7 +474,7 @@ public class ByteUtils { | ||||
|     /** | ||||
|      * UDInt 无符号整形 4个字节  =》 Long | ||||
|      * */ | ||||
|     public static List<Long> toUDIntArray(byte[] b) throws UnsupportedEncodingException { | ||||
|     public static List<Long> toUDIntArray(byte[] b) { | ||||
|         List<Long> res = new ArrayList<>(); | ||||
|         int i=0; | ||||
|         while ((i+4)<=b.length){ | ||||
| @@ -483,7 +489,7 @@ public class ByteUtils { | ||||
|     /** | ||||
|      * SInt 无符号整形 1个字节  =》 Integer | ||||
|      * */ | ||||
|     public static List<Integer> toSIntArray(byte[] b) throws UnsupportedEncodingException { | ||||
|     public static List<Integer> toSIntArray(byte[] b) { | ||||
|         List<Integer> res = new ArrayList<>(); | ||||
|         for(int i=0;i<b.length;i++){ | ||||
|             res.add(toInt(b[i])); | ||||
| @@ -493,7 +499,7 @@ public class ByteUtils { | ||||
|     /** | ||||
|      * Int 无符号整形 2个字节  =》 Integer | ||||
|      * */ | ||||
|     public static List<Integer> toIntArray(byte[] b) throws UnsupportedEncodingException { | ||||
|     public static List<Integer> toIntArray(byte[] b) { | ||||
|         List<Integer> res = new ArrayList<>(); | ||||
|         int i=0; | ||||
|         while ((i+2)<=b.length){ | ||||
| @@ -507,7 +513,7 @@ public class ByteUtils { | ||||
|     /** | ||||
|      * DInt 无符号整形 4个字节  =》 Integer | ||||
|      * */ | ||||
|     public static List<Integer> toDIntArray(byte[] b) throws UnsupportedEncodingException { | ||||
|     public static List<Integer> toDIntArray(byte[] b) { | ||||
|         List<Integer> res = new ArrayList<>(); | ||||
|         int i=0; | ||||
|         while ((i+4)<=b.length){ | ||||
|   | ||||
| @@ -0,0 +1,355 @@ | ||||
| package com.qgs.dc.s7.my.s7connector.enmuc; | ||||
|  | ||||
|  | ||||
| import com.qgs.dc.s7.my.s7connector.api.DaveArea; | ||||
| import com.qgs.dc.s7.my.s7connector.api.S7Connector; | ||||
| import com.qgs.dc.s7.my.s7connector.api.factory.S7ConnectorFactory; | ||||
| import com.qgs.dc.s7.my.s7connector.api.utils.ByteUtils; | ||||
| import com.qgs.dc.s7.my.s7connector.exception.S7Exception; | ||||
| import com.qgs.dc.s7.my.s7connector.type.PlcVar; | ||||
| import com.qgs.dc.s7.my.s7connector.utils.CommonFunctions; | ||||
| import com.qgs.dc.s7.retry.S7RetryTemplate; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * @Desc: "" | ||||
|  * @Author: caixiang | ||||
|  * @DATE: 2022/1/15 13:01 | ||||
|  */ | ||||
| public enum S7ClientNew { | ||||
|     //TODO 步骤1  这里是配置多PLC 的,,,有多个plc 就在这里配置一个枚举类 | ||||
|     //1500    西门子200smart、1200、1500默认的 机架号=0  槽位号=1;  300/400 默认的  机架-0  插槽-2 | ||||
|     S7_1200("192.168.0.52",0,1,1,PlcVarActual.HeartBeatFor1200), | ||||
|  | ||||
|     S7_1500("192.168.0.51",0,1,1,PlcVarActual.HeartBeat), | ||||
|     //1500  机架-0  插槽-1 | ||||
|     //后续 在这里扩展 多PLC应用。 | ||||
|     ; | ||||
|     private String host; | ||||
|     //默认 0   机架号 | ||||
|     private Integer rack; | ||||
|     //默认 0 | ||||
|     private Integer slot; | ||||
|  | ||||
|     //心跳变量,如果plc没有让电控的人加一个,这个是必填的 | ||||
|     private PlcVarActual heartBeat; | ||||
|  | ||||
|     private List<S7Connector> connections; | ||||
|     //coreSize 是线程池的大小 | ||||
|     private Integer coreSize; | ||||
|     //pickOne 就是一个初始化 的轮询取余值 | ||||
|     private int pickOne; | ||||
|     private static final Logger logger = LoggerFactory.getLogger(S7ClientNew.class); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     //coreSize 是线程池的数量 | ||||
|     S7ClientNew(String host, Integer rack, Integer slot, Integer coreSize, PlcVarActual heartBeat){ | ||||
|         this.host = host; | ||||
|         this.rack = rack; | ||||
|         this.slot = slot; | ||||
|         this.pickOne = 0; | ||||
|  | ||||
|         this.coreSize = coreSize; | ||||
|  | ||||
|         connections = new ArrayList<>(); | ||||
|         connectionPool(); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public String getHost(){ | ||||
|         return this.host; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * PlcVar(byte[])  转  java对象    对照表 | ||||
|      * 单体变量 | ||||
|      * Bool       ===>      Boolean | ||||
|      * LREAL      ===>      Double | ||||
|      * REAL       ===>      Float | ||||
|      * DATE       ===>      String(yyyy-MM-dd 这种形式的类型) | ||||
|      * DTL        ===>      String("年-月-日-工作日-时-分-秒" 这种格式) | ||||
|      * TIME       ===>      Integer(单位 ms) | ||||
|      * USINT      ===>      Integer | ||||
|      * SINT       ===>      Integer | ||||
|      * UINT       ===>      Integer | ||||
|      * INT        ===>      Integer | ||||
|      * DINT       ===>      Integer | ||||
|      * UINT       ===>      Long | ||||
|      * Byte       ===>      Integer(有符号)(默认) | ||||
|      *                     Integer(无符号)(后续扩展) | ||||
|      * Char       ===>      Character | ||||
|      * WChar      ===>      Character | ||||
|      * String     ===>      String                      (特殊) | ||||
|  | ||||
|  | ||||
|      * 数组变量 | ||||
|      * BoolArray      ===>      List<Boolean> | ||||
|      * ByteArray      ===>      List<Byte> | ||||
|      * WordArray      ===>      List<Integer> | ||||
|      * DWordArray     ===>      List<Integer> | ||||
|      * CharArray      ===>      List<Character> | ||||
|      * SIntArray      ===>      List<Integer> | ||||
|      * IntArray       ===>      List<Integer> | ||||
|      * DIntArray      ===>      List<Integer> | ||||
|      * UIntArray      ===>      List<Integer> | ||||
|      * USIntArray     ===>      List<Integer> | ||||
|      * UDIntArray     ===>      List<Long> | ||||
|      * StringArray    ===>      String[]        (特殊) | ||||
|      * | ||||
|      * 如果返回null,就代表出现了异常,并且尝试了 retryMax 次数,并且尝试重置连接 | ||||
|      * */ | ||||
|     public Object read(DaveArea area, Integer areaNumber, Integer byteOffset, Integer bitOffset, Integer length, Integer strSizes, PlcVar type) { | ||||
|         S7Connector connector = getConnector(); | ||||
|         return S7RetryTemplate.getInstance().execute( | ||||
|                 context -> { | ||||
|                     //String 类型比较特殊。 String[] 也是同理,Sring数组里面的子项 也是有两个字节的 readBytes。 | ||||
|                     if(type.equals(PlcVar.STRING)){ | ||||
|                         Integer readBytes = 2; | ||||
|                         byte[] read = connector.read( | ||||
|                                 area, | ||||
|                                 areaNumber, | ||||
|                                 readBytes, | ||||
|                                 byteOffset, | ||||
|                                 bitOffset, | ||||
|                                 type.getTransportSize() | ||||
|                         ); | ||||
|  | ||||
|                         Integer allLength = Integer.valueOf(read[1])+2; | ||||
|                         byte[] readF = connector.read( | ||||
|                                 area, | ||||
|                                 areaNumber, | ||||
|                                 allLength, | ||||
|                                 byteOffset, | ||||
|                                 bitOffset, | ||||
|                                 type.getTransportSize() | ||||
|                         ); | ||||
|                         return type.toObject(readF); | ||||
|                     }else if(type.equals(PlcVar.BOOL_Array)){ | ||||
|  | ||||
|                         byte[] read = connector.read( | ||||
|                                 area, | ||||
|                                 areaNumber, | ||||
|                                 CommonFunctions.exactDivision(length,8), | ||||
|                                 byteOffset, | ||||
|                                 bitOffset, | ||||
|                                 type.getTransportSize() | ||||
|                         ); | ||||
|                         List<Boolean> booleans = ByteUtils.toBoolArray(read); | ||||
|                         List<Boolean> res = new ArrayList<Boolean>(); | ||||
|                         for(int i=0;i<length;i++){ | ||||
|                             res.add(i,booleans.get(i)); | ||||
|                         } | ||||
|                         return res; | ||||
|                     }else if(type.equals(PlcVar.STRING_Array)){ | ||||
|                         Integer arrayLength =  length; | ||||
|                         Integer strSize =  strSizes; | ||||
|  | ||||
|                         byte[] read = connector.read( | ||||
|                                 area, | ||||
|                                 areaNumber, | ||||
|                                 arrayLength*(strSize+2), | ||||
|                                 byteOffset, | ||||
|                                 bitOffset, | ||||
|                                 type.getTransportSize() | ||||
|                         ); | ||||
|                         return ByteUtils.toStrArray(read, arrayLength, strSize); | ||||
|                     }else { | ||||
|                         Integer readBytes = type.getTransportSize().getSizeInBytes() * length; | ||||
|                         byte[] read = connector.read( | ||||
|                                 area, | ||||
|                                 areaNumber, | ||||
|                                 readBytes, | ||||
|                                 byteOffset, | ||||
|                                 bitOffset, | ||||
|                                 type.getTransportSize() | ||||
|                         ); | ||||
|                         return type.toObject(read); | ||||
|                     } | ||||
|                 }, | ||||
|                 context -> { | ||||
|                     logger.info("S7-Retry : 已达到最大重试次数: "+S7RetryTemplate.getMaxRetryTimes()+", 现在尝试重新连接"); | ||||
|                     if(replaceConnector(connector)==1){ | ||||
|                         logger.info("S7-Retry-Read 现在恢复成功,创建新connection成功"); | ||||
|                         return null; | ||||
|                     }else { | ||||
|                         logger.info("S7-Retry-Read 现在恢复失败,创建新connection失败"); | ||||
|                         return null; | ||||
|                     } | ||||
|                 } | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * | ||||
|      * eg : | ||||
|      *      Object newValue = Boolean.FALSE | ||||
|      *      s7Service.write(PlcVarActual.HeartBeat, newValue, S7Client.S7_1200); | ||||
|      * | ||||
|      * PlcVar(byte[])  转  java对象    对照表 | ||||
|      * 单体变量 | ||||
|      * Bool       ===>      Object newValue = Boolean.FALSE | ||||
|      * LREAL      ===>      Object newValue = Boolean.FALSE | ||||
|      * REAL       ===>      Object newValue = Boolean.FALSE | ||||
|      * DATE       ===>      暂时没需求(有问题找我) | ||||
|      * DTL        ===>      暂时没需求(有问题找我) | ||||
|      * TIME       ===>      暂时没需求(有问题找我) | ||||
|      * USINT      ===>      Object newValue = new Integer(1) | ||||
|      * SINT       ===>      Object newValue = new Integer(1) | ||||
|      * UINT       ===>      Object newValue = new Integer(1) | ||||
|      * INT        ===>      Object newValue = new Integer(1) | ||||
|      * DINT       ===>      Object newValue = new Integer(1) | ||||
|      * UINT       ===>      Object newValue = new Integer(1) | ||||
|      * Byte       ===>      Object newValue = 0x11 | ||||
|      * | ||||
|      * Char       ===>      Object newValue = 'a' | ||||
|      * WChar      ===>      Object newValue = '菜' | ||||
|      * String     ===>      Object newValue = '你好啊'      (特殊) | ||||
|  | ||||
|  | ||||
|      * 数组变量 | ||||
|      *      注意:在write的时候,你write的数量  一定要和  plc中存在的数量一一对应 | ||||
|      * BoolArray      ===>      boolean[] booleanArray = new boolean[2];  .... 赋予值 | ||||
|      * ByteArray      ===>      byte[] write_byteArrays = new byte[2]; | ||||
|      * WordArray      ===>      short[] shortArrays_content = new short[2]; | ||||
|      * DWordArray     ===>      int[] intArrays_content = new int[2]; | ||||
|      * CharArray      ===>      char[] charArrays_content = new char[2]; | ||||
|      * SIntArray      ===>      int[] sintArrays_content = new int[2]; | ||||
|      * IntArray       ===>      int[] iintArrays_content = new int[2]; | ||||
|      * DIntArray      ===>      int[] dintArrays_content = new int[2]; | ||||
|      * UIntArray      ===>      int[] uintArrays_content = new int[3]; | ||||
|      * USIntArray     ===>      int[] usintArrays_content = new int[3]; | ||||
|      * UDIntArray     ===>      int[] udintArrays_content = new int[3]; | ||||
|      * StringArray    ===>      String[] stringArrays_content = new String[3]; | ||||
|      * //如果有其他数据类型  这里没有找我扩展 | ||||
|      * | ||||
|      * | ||||
|      * */ | ||||
|     public void write(DaveArea area, Integer areaNumber, Integer byteOffset, Integer bitOffset,Integer strSize, PlcVar type, Object newValue) throws Exception { | ||||
|         S7Connector connector = getConnector(); | ||||
|  | ||||
|         S7RetryTemplate.getInstance().execute( | ||||
|                context -> { | ||||
|                    //String 类型比较特殊。 String[] 也是同理,Sring数组里面的子项 也是有两个字节的 readBytes。 | ||||
|                    if(type.equals(PlcVar.STRING)){ | ||||
|                        connector.write( | ||||
|                                area, | ||||
|                                areaNumber, | ||||
|                                byteOffset, | ||||
|                                bitOffset, | ||||
|                                ByteUtils.strToBytes(newValue.toString(), strSize), | ||||
|                                type | ||||
|                        ); | ||||
|                    }else if(type.equals(PlcVar.BOOL_Array)){ | ||||
|                        connector.write( | ||||
|                                area, | ||||
|                                areaNumber, | ||||
|                                byteOffset, | ||||
|                                bitOffset, | ||||
|                                ByteUtils.toByteArray((boolean[])newValue), | ||||
|                                type | ||||
|                        ); | ||||
|                    }else if(type.equals(PlcVar.STRING_Array)){ | ||||
|                        //todo here 检查 read write service | ||||
|                        connector.write( | ||||
|                                area, | ||||
|                                areaNumber, | ||||
|                                byteOffset, | ||||
|                                bitOffset, | ||||
|                                ByteUtils.strArrayToBytes((String[])newValue, strSize), | ||||
|                                type | ||||
|                        ); | ||||
|                    }else { | ||||
|                        byte[] bytes = type.toBytes(newValue); | ||||
|                        connector.write( | ||||
|                                area, | ||||
|                                areaNumber, | ||||
|                                byteOffset, | ||||
|                                bitOffset, | ||||
|                                bytes, | ||||
|                                type | ||||
|                        ); | ||||
|                    } | ||||
|                    return null; | ||||
|                }, | ||||
|                context -> { | ||||
|                    logger.info("S7-Retry-Write : 已达到最大重试次数: "+S7RetryTemplate.getMaxRetryTimes()+", 现在尝试重新连接"); | ||||
|                    if( replaceConnector(connector) == 1 ){ | ||||
|                        logger.info("S7-Retry-Write 现在恢复成功,创建新connection成功"); | ||||
|                        return null; | ||||
|                    }else { | ||||
|                        logger.info("S7-Retry-Write 现在恢复失败,创建新connection失败"); | ||||
|                        return null; | ||||
|                    } | ||||
|                } | ||||
|         ); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * desc: 传入的connection 是需要被替换的 | ||||
|      * return: | ||||
|      *      1   代表替换成功 | ||||
|      *      -1  代表替换失败(创建connection失败,原因:出现异常.原来的connection也被舍弃掉了) | ||||
|      * */ | ||||
|     private Integer replaceConnector(S7Connector oldOne){ | ||||
|         connections.remove(oldOne); | ||||
|         S7Connector connect = connect(host, rack, slot); | ||||
|         if(connect == null){ | ||||
|             return -1; | ||||
|         }else { | ||||
|             connections.add(connect); | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public S7Connector getConnector() { | ||||
|         int size = connections.size(); | ||||
|         S7Connector s7Connector = connections.get((pickOne + size) % size); | ||||
|         pickOne+=1; | ||||
|         pickOne = (pickOne)%size; | ||||
|         return s7Connector; | ||||
|     } | ||||
|  | ||||
|     private S7Connector connect(String host,Integer rack,Integer slot ){ | ||||
|         try { | ||||
|             S7Connector connector = S7ConnectorFactory | ||||
|                     .buildTCPConnector() | ||||
|                     .withHost(host) | ||||
|                     .withRack(rack) //optional   rack 是机架号 | ||||
|                     .withSlot(slot) //optional   slot 是插槽号 | ||||
|                     .build(); | ||||
|             return connector; | ||||
|         }catch (S7Exception e){ | ||||
| //            logger.info("创建S7Connector  连接失败,原因:"+e.getMessage()); | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     private void resetConnetctions(){ | ||||
|         this.connections = new ArrayList<S7Connector>(); | ||||
|         connectionPool(); | ||||
|     } | ||||
|  | ||||
|     private void connectionPool(){ | ||||
|         for(int i=0;i<coreSize;i++){ | ||||
|             S7Connector connect = connect(host, rack, slot); | ||||
|             if(connect!=null){ | ||||
|                 connections.add(connect); | ||||
|             } | ||||
|         } | ||||
|         //todo 在plc上新增一个 变量来解决 心跳问题 okok | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,64 @@ | ||||
| /* | ||||
| Copyright 2016 S7connector members (github.com/s7connector) | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| package com.qgs.dc.s7.my.s7connector.exception; | ||||
|  | ||||
| /** | ||||
|  * The Class S7Exception is an exception related to S7 Communication | ||||
|  */ | ||||
| public final class S7CheckResultException extends RuntimeException { | ||||
|  | ||||
| 	/** The Constant serialVersionUID. */ | ||||
| 	private static final long serialVersionUID = -4761415733559374116L; | ||||
|  | ||||
| 	/** | ||||
| 	 * Instantiates a new s7 exception. | ||||
| 	 */ | ||||
| 	public S7CheckResultException() { | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Instantiates a new s7 exception. | ||||
| 	 * | ||||
| 	 * @param message | ||||
| 	 *            the message | ||||
| 	 */ | ||||
| 	public S7CheckResultException(final String message) { | ||||
| 		super(message); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Instantiates a new s7 exception. | ||||
| 	 * | ||||
| 	 * @param message | ||||
| 	 *            the message | ||||
| 	 * @param cause | ||||
| 	 *            the cause | ||||
| 	 */ | ||||
| 	public S7CheckResultException(final String message, final Throwable cause) { | ||||
| 		super(message, cause); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Instantiates a new s7 exception. | ||||
| 	 * | ||||
| 	 * @param cause | ||||
| 	 *            the cause | ||||
| 	 */ | ||||
| 	public S7CheckResultException(final Throwable cause) { | ||||
| 		super(cause); | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,66 @@ | ||||
| /* | ||||
| Copyright 2016 S7connector members (github.com/s7connector) | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| package com.qgs.dc.s7.my.s7connector.exception; | ||||
|  | ||||
| import java.io.IOException; | ||||
|  | ||||
| /** | ||||
|  * The Class S7IOException is an exception related to S7 Communication | ||||
|  */ | ||||
| public final class S7IOException extends RuntimeException { | ||||
|  | ||||
| 	/** The Constant serialVersionUID. */ | ||||
| 	private static final long serialVersionUID = -4761415733559374116L; | ||||
|  | ||||
| 	/** | ||||
| 	 * Instantiates a new s7 exception. | ||||
| 	 */ | ||||
| 	public S7IOException() { | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Instantiates a new s7 exception. | ||||
| 	 * | ||||
| 	 * @param message | ||||
| 	 *            the message | ||||
| 	 */ | ||||
| 	public S7IOException(final String message) { | ||||
| 		super(message); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Instantiates a new s7 exception. | ||||
| 	 * | ||||
| 	 * @param message | ||||
| 	 *            the message | ||||
| 	 * @param cause | ||||
| 	 *            the cause | ||||
| 	 */ | ||||
| 	public S7IOException(final String message, final Throwable cause) { | ||||
| 		super(message, cause); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Instantiates a new s7 exception. | ||||
| 	 * | ||||
| 	 * @param cause | ||||
| 	 *            the cause | ||||
| 	 */ | ||||
| 	public S7IOException(final Throwable cause) { | ||||
| 		super(cause); | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,64 @@ | ||||
| /* | ||||
| Copyright 2016 S7connector members (github.com/s7connector) | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| package com.qgs.dc.s7.my.s7connector.exception; | ||||
|  | ||||
| /** | ||||
|  * The Class S7Exception is an exception related to S7 Communication | ||||
|  */ | ||||
| public final class S7ParseDataException extends RuntimeException { | ||||
|  | ||||
| 	/** The Constant serialVersionUID. */ | ||||
| 	private static final long serialVersionUID = -4761415733559374116L; | ||||
|  | ||||
| 	/** | ||||
| 	 * Instantiates a new s7 exception. | ||||
| 	 */ | ||||
| 	public S7ParseDataException() { | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Instantiates a new s7 exception. | ||||
| 	 * | ||||
| 	 * @param message | ||||
| 	 *            the message | ||||
| 	 */ | ||||
| 	public S7ParseDataException(final String message) { | ||||
| 		super(message); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Instantiates a new s7 exception. | ||||
| 	 * | ||||
| 	 * @param message | ||||
| 	 *            the message | ||||
| 	 * @param cause | ||||
| 	 *            the cause | ||||
| 	 */ | ||||
| 	public S7ParseDataException(final String message, final Throwable cause) { | ||||
| 		super(message, cause); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Instantiates a new s7 exception. | ||||
| 	 * | ||||
| 	 * @param cause | ||||
| 	 *            the cause | ||||
| 	 */ | ||||
| 	public S7ParseDataException(final Throwable cause) { | ||||
| 		super(cause); | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -17,6 +17,8 @@ package com.qgs.dc.s7.my.s7connector.impl; | ||||
|  | ||||
| import com.qgs.dc.s7.my.s7connector.api.DaveArea; | ||||
| import com.qgs.dc.s7.my.s7connector.api.S7Connector; | ||||
| import com.qgs.dc.s7.my.s7connector.exception.S7CheckResultException; | ||||
| import com.qgs.dc.s7.my.s7connector.exception.S7Exception; | ||||
| import com.qgs.dc.s7.my.s7connector.impl.nodave.Nodave; | ||||
| import com.qgs.dc.s7.my.s7connector.impl.nodave.S7Connection; | ||||
| import com.qgs.dc.s7.my.s7connector.type.PlcVar; | ||||
| @@ -32,7 +34,7 @@ public abstract class S7BaseConnection implements S7Connector { | ||||
|  | ||||
| 	/** The Constant MAX_SIZE. */ | ||||
| 	//private static final int MAX_SIZE = 96;     //原版96 ;; ioserver 127  ;; | ||||
| 	private static final int MAX_SIZE = 212;     //S7-1200-maxReadBytes = 212  ;;  S7-1200-maxReadBytes = 452 | ||||
| 	private static final int MAX_SIZE = 212;     //S7-1200-maxReadBytes = 212  ;;  S7-1500-maxReadBytes = 452 | ||||
|  | ||||
| 	/** The Constant PROPERTY_AREA. */ | ||||
| 	public static final String PROPERTY_AREA = "area"; | ||||
| @@ -52,11 +54,11 @@ public abstract class S7BaseConnection implements S7Connector { | ||||
| 	 * @param libnodaveResult | ||||
| 	 *            the libnodave result | ||||
| 	 */ | ||||
| 	public static void checkResult(final int libnodaveResult) throws Exception { | ||||
| 	public static void checkResult(final int libnodaveResult) { | ||||
| 		if (libnodaveResult != Nodave.RESULT_OK) { | ||||
| 			final String msg = Nodave.strerror(libnodaveResult); | ||||
| //			throw new IllegalArgumentException("Result: " + msg); | ||||
| 			throw new Exception(msg); | ||||
| 			throw new S7CheckResultException("errMsg : "+msg); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -87,7 +89,7 @@ public abstract class S7BaseConnection implements S7Connector { | ||||
|  | ||||
| 	/** {@inheritDoc} */ | ||||
| 	@Override | ||||
| 	public synchronized byte[] read(final DaveArea area, final int areaNumber, final int bytes, final int offset) throws Exception { | ||||
| 	public synchronized byte[] read(final DaveArea area, final int areaNumber, final int bytes, final int offset) { | ||||
| 		if (bytes > MAX_SIZE) { | ||||
| 			final byte[] ret = new byte[bytes]; | ||||
| 			//注意这里 嵌套了 递归,让无限递归去解决 MAX_SIZE的问题。 | ||||
| @@ -108,7 +110,7 @@ public abstract class S7BaseConnection implements S7Connector { | ||||
| 		} | ||||
| 	} | ||||
| 	@Override | ||||
| 	public synchronized byte[] read(final DaveArea area, final int areaNumber, final int bytes, final int offset, int bitOffset, TransportSize transportSize) throws Exception { | ||||
| 	public synchronized byte[] read(final DaveArea area, final int areaNumber, final int bytes, final int offset, int bitOffset, TransportSize transportSize) { | ||||
| 		if(bitOffset==0){ | ||||
| 			return read(area,areaNumber,bytes,offset); | ||||
| 		} | ||||
| @@ -128,6 +130,7 @@ public abstract class S7BaseConnection implements S7Connector { | ||||
| 			final byte[] buffer = new byte[bytes]; | ||||
| 			final int ret = this.dc.readBytes(area, areaNumber, offset,bitOffset, bytes, buffer,transportSize); | ||||
|  | ||||
| 			//thr resultException | ||||
| 			checkResult(ret); | ||||
| 			return buffer; | ||||
| 		} | ||||
| @@ -135,7 +138,7 @@ public abstract class S7BaseConnection implements S7Connector { | ||||
|  | ||||
| 	/** {@inheritDoc} */ | ||||
| 	@Override | ||||
| 	public synchronized void write(final DaveArea area, final int areaNumber, final int offset, final byte[] buffer) throws Exception { | ||||
| 	public synchronized void write(final DaveArea area, final int areaNumber, final int offset, final byte[] buffer) { | ||||
| 		if (buffer.length > MAX_SIZE) { | ||||
| 			// Split buffer | ||||
| 			final byte[] subBuffer = new byte[MAX_SIZE]; | ||||
| @@ -155,7 +158,7 @@ public abstract class S7BaseConnection implements S7Connector { | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public synchronized void write(final DaveArea area, final int areaNumber, final int byteOffset, final int bitOffset, final byte[] buffer, PlcVar var) throws Exception { | ||||
| 	public synchronized void write(final DaveArea area, final int areaNumber, final int byteOffset, final int bitOffset, final byte[] buffer, PlcVar var) { | ||||
| 		if(bitOffset==0){ | ||||
| 			write(area,areaNumber,byteOffset,buffer); | ||||
| 			return; | ||||
|   | ||||
| @@ -15,6 +15,7 @@ limitations under the License. | ||||
| */ | ||||
| package com.qgs.dc.s7.my.s7connector.impl.nodave; | ||||
|  | ||||
| import com.qgs.dc.s7.my.s7connector.exception.S7IOException; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| @@ -45,7 +46,7 @@ public final class PLCinterface { | ||||
| 		this.protocol = protocol; | ||||
| 	} | ||||
|  | ||||
| 	public int read(final byte[] b, int start, int len) { | ||||
| 	public int read(final byte[] b, int start, int len){ | ||||
| 		int res; | ||||
| 		try { | ||||
| 			int retry = 0; | ||||
| @@ -67,18 +68,20 @@ public final class PLCinterface { | ||||
| 			} | ||||
| 			return res; | ||||
| 		} catch (final IOException e) { | ||||
| 			logger.info("Socket read字节流失败: "+e); | ||||
| 			return 0; | ||||
| 			String errMsg = "Socket read字节流失败: "+e.getMessage(); | ||||
| 			logger.info(errMsg); | ||||
| 			throw new S7IOException(errMsg); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public int write(final byte[] b, final int start, final int len) { | ||||
| 	public int write(final byte[] b, final int start, final int len){ | ||||
| 		try { | ||||
| 			this.out.write(b, start, len); | ||||
| 			return 1; | ||||
| 		} catch (final IOException e) { | ||||
| 			logger.info("Socket write字节流失败: "+e); | ||||
| 			return 0; | ||||
| 			String errMsg = "Socket write字节流失败: "+e.getMessage(); | ||||
| 			logger.info(errMsg); | ||||
| 			throw new S7IOException(errMsg); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -76,7 +76,7 @@ public abstract class S7Connection { | ||||
| 	 * it's NULL you can get your data from the resultPointer in daveConnection | ||||
| 	 * long as you do not send further requests. | ||||
| 	 */ | ||||
| 	public ResultSet execReadRequest(final PDU p) { | ||||
| 	public ResultSet execReadRequest(final PDU p) throws Exception { | ||||
| 		PDU p2; | ||||
| 		int errorState; | ||||
| 		errorState = this.exchange(p); | ||||
| @@ -269,7 +269,7 @@ public abstract class S7Connection { | ||||
| 	 * build the PDU for a PDU length negotiation | ||||
| 	 * 构建第二次握手 | ||||
| 	 */ | ||||
| 	public int negPDUlengthRequest() { | ||||
| 	public int negPDUlengthRequest() throws Exception { | ||||
| 		int res; | ||||
| 		final PDU p = new PDU(this.msgOut, this.PDUstartOut); | ||||
| 		//S7-Param  构造 | ||||
| @@ -320,7 +320,7 @@ public abstract class S7Connection { | ||||
| 		final PDU p1 = new PDU(this.msgOut, this.PDUstartOut); | ||||
| 		p1.initReadRequest(); | ||||
| 		p1.addVarToReadRequest(area, DBnum, start, len); | ||||
| 		//发送read var request | ||||
| 		//通过tcp链接   发送read var request,thr S7IOException | ||||
| 		res = this.exchange(p1); | ||||
| 		if (res != Nodave.RESULT_OK) { | ||||
| 			this.semaphore.release(); | ||||
|   | ||||
| @@ -17,6 +17,7 @@ package com.qgs.dc.s7.my.s7connector.impl.nodave; | ||||
|  | ||||
| import com.qgs.dc.s7.my.s7connector.api.utils.ByteUtils; | ||||
| import com.qgs.dc.s7.my.s7connector.enmuc.S7Client; | ||||
| import com.qgs.dc.s7.my.s7connector.exception.S7IOException; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| @@ -59,7 +60,7 @@ public final class TCPConnection extends S7Connection { | ||||
| 	 * | ||||
| 	 * @return the int | ||||
| 	 */ | ||||
| 	public int connectPLC() { | ||||
| 	public int connectPLC() throws Exception { | ||||
| 		//COTP包 字节流(是上位机 和plc进行的第一次握手) | ||||
| 		final byte[] b4 = {    //b4.length = 18 | ||||
| 				(byte) 0x11,	//(16进制)当前字节以后的字节数 | ||||
| @@ -113,7 +114,7 @@ public final class TCPConnection extends S7Connection { | ||||
| 	 * 		    0 代表成功 | ||||
| 	 * */ | ||||
| 	@Override | ||||
| 	public int exchange(final PDU p1) { | ||||
| 	public int exchange(final PDU p1){ | ||||
| 		this.msgOut[4] = (byte) 0x02;  //当前字节以后的字节数(也就是下面两个字节) | ||||
| 		this.msgOut[5] = (byte) 0xf0;  //PDU Type | ||||
| 		this.msgOut[6] = (byte) 0x80;  //TPDU number (如果这个字节首位为1 代表就是最后一个传输单元了 如1000 0000 ;;  如果首字母不为1 就代表这个Request是比较长的要分多个unit传输,后7位就代表传输单元序号) | ||||
| @@ -123,9 +124,9 @@ public final class TCPConnection extends S7Connection { | ||||
| 		if(writeRes!=0 && readRes!=0){ | ||||
| 			return 0; | ||||
| 		}else { | ||||
|  | ||||
| 			logger.info("exchange 出现了问题:① writeRes:"+(writeRes==0?"writeISOPacket成功":"writeISOPacket失败")+"② readRes:"+(readRes==0?"readISOPacket成功":"readISOPacket失败")); | ||||
| 			return 1    ; | ||||
| 			String errMsg = "exchange 出现了问题:① writeRes:"+(writeRes==0?"writeISOPacket成功":"writeISOPacket失败")+"② readRes:"+(readRes==0?"readISOPacket成功":"readISOPacket失败"); | ||||
| 			logger.info(errMsg); | ||||
| 			throw new S7IOException(errMsg); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -133,15 +134,14 @@ public final class TCPConnection extends S7Connection { | ||||
| 	 * Read iso packet. | ||||
| 	 * | ||||
| 	 * @return the int | ||||
| 	 * 			0     ==>   不成功 | ||||
| 	 * 			0     ==>   不成功(异常) | ||||
| 	 * 		    -1    ==>   读到一个空的字节流 (这种情况很少) | ||||
| 	 * 			其他   ==>   成功 | ||||
| 	 */ | ||||
| 	protected int readISOPacket() { | ||||
| 	protected int readISOPacket(){ | ||||
| 		//read return 为0 就是异常 | ||||
| 		int res = this.iface.read(this.msgIn, 0, 4); | ||||
| 		if (res == 4) { | ||||
| //			final int len = (0x100 * this.msgIn[2]) + this.msgIn[3]; //读取字节数 这串是bug代码 | ||||
| 			final int len = (0x100 * ByteUtils.toUInt(this.msgIn[2])) + ByteUtils.toUInt(this.msgIn[3]); | ||||
| 			res += this.iface.read(this.msgIn, 4, len); | ||||
| 		} else { | ||||
| @@ -159,7 +159,7 @@ public final class TCPConnection extends S7Connection { | ||||
| 	 * 			1   ==> 成功 | ||||
| 	 * 			0   ==> 不成功(出现异常了) | ||||
| 	 */ | ||||
| 	protected int sendISOPacket(int size) { | ||||
| 	protected int sendISOPacket(int size){ | ||||
| 		size += 4; | ||||
| 		//下面包装的 是TPKT 字节包(第一次握手) | ||||
| 		this.msgOut[0] = (byte) 0x03;            //Version ,默认版本3 | ||||
|   | ||||
| @@ -330,7 +330,7 @@ public enum PlcVar { | ||||
|      * | ||||
|      * | ||||
|      * */ | ||||
|     public Object toObject(byte[] value) throws ParseException, UnsupportedEncodingException { | ||||
|     public Object toObject(byte[] value) { | ||||
|         if(!isArray){ | ||||
|             Object res = null; | ||||
|             switch (dataType) { | ||||
|   | ||||
							
								
								
									
										60
									
								
								src/main/java/com/qgs/dc/s7/retry/S7RetryTemplate.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/main/java/com/qgs/dc/s7/retry/S7RetryTemplate.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| package com.qgs.dc.s7.retry; | ||||
|  | ||||
| import com.qgs.dc.s7.my.s7connector.exception.S7CheckResultException; | ||||
| import com.qgs.dc.s7.my.s7connector.exception.S7IOException; | ||||
| import org.springframework.remoting.RemoteAccessException; | ||||
| import org.springframework.retry.backoff.FixedBackOffPolicy; | ||||
| import org.springframework.retry.policy.SimpleRetryPolicy; | ||||
| import org.springframework.retry.support.RetryTemplate; | ||||
|  | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * @author caixiang | ||||
|  * @description 重试模板和重试策略 | ||||
|  */ | ||||
| public class S7RetryTemplate extends RetryTemplate { | ||||
|  | ||||
|     private volatile static S7RetryTemplate instance = null; | ||||
|     /** | ||||
|      * 重试间隔时间ms,默认1000ms | ||||
|      * */ | ||||
|     private static long fixedPeriodTime = 500L; | ||||
|     /** | ||||
|      * 最大重试次数,默认为3 | ||||
|      */ | ||||
|     private static int maxRetryTimes = 3; | ||||
|     /** | ||||
|      * 表示哪些异常需要重试,key表示异常的字节码,value为true表示需要重试 | ||||
|      */ | ||||
|     private static Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>(); | ||||
|     private S7RetryTemplate() { | ||||
|         // 代表S7IOException 这个异常是需要重试的(true), 如果你想设置这个异常不去重试,那么可以把它设置为false。 | ||||
|         exceptionMap.put(S7IOException.class,true); | ||||
|         exceptionMap.put(S7CheckResultException.class,true); | ||||
|  | ||||
|     } | ||||
|     public static int getMaxRetryTimes() { | ||||
|         return maxRetryTimes; | ||||
|     } | ||||
|  | ||||
|     public static S7RetryTemplate getInstance() { | ||||
|         if (instance == null) { | ||||
|             synchronized (S7RetryTemplate.class) { | ||||
|                 if (instance == null) { | ||||
|                     FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy(); | ||||
|                     // 定义重试间隔-间隔 fixedPeriodTime ms再重试,总共重试3次 | ||||
|                     backOffPolicy.setBackOffPeriod(fixedPeriodTime); | ||||
|                     instance = new S7RetryTemplate(); | ||||
|                     // 定义重试次数- maxRetryTimes | ||||
|                     SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(maxRetryTimes, exceptionMap); | ||||
|                     instance.setRetryPolicy(retryPolicy); | ||||
|  | ||||
|                     instance.setBackOffPolicy(backOffPolicy); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return instance; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										39
									
								
								src/main/java/com/qgs/dc/s7/retrydemo/RetryDemoTask.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/main/java/com/qgs/dc/s7/retrydemo/RetryDemoTask.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| package com.qgs.dc.s7.retrydemo; | ||||
|  | ||||
|  | ||||
| import org.apache.commons.lang3.RandomUtils; | ||||
| import org.springframework.remoting.RemoteAccessException; | ||||
|  | ||||
| /** | ||||
|  * @Author: cx | ||||
|  * @Description: | ||||
|  */ | ||||
| public class RetryDemoTask { | ||||
|     /** | ||||
|      * 重试方法 | ||||
|      * @return | ||||
|      */ | ||||
|     public static boolean retryTask(String param)  { | ||||
|         System.out.println("retry-task : 收到请求参数:"+param); | ||||
|  | ||||
|         int i = RandomUtils.nextInt(0,11); | ||||
|         System.out.println("retry-task : 随机生成的数:"+i); | ||||
|         if (i == 0) { | ||||
|             System.out.println("retry-task : 为0,抛出参数异常."); | ||||
|             //因为Illeague这个异常我们没有在exceptionMap里面配置,所以 抛出这个异常后 | ||||
|             //spring-retry不会进行重试,而是会直接进入recovery函数 | ||||
|             throw new IllegalArgumentException("retry-task : 参数异常"); | ||||
|         }else if (i  == 1){ | ||||
|             System.out.println("retry-task : 为1,返回true."); | ||||
|             return true; | ||||
|         }else if (i == 2){ | ||||
|             System.out.println("retry-task : 为2,返回false."); | ||||
|             return false; | ||||
|         }else{ | ||||
|             //因为RemoteAccessExcep这个异常我们在exceptionMap里面配置了,所以 抛出这个异常后 | ||||
|             //spring-retry会进行重试 | ||||
|             System.out.println("retry-task : 大于2,抛出自定义异常."); | ||||
|             throw new RemoteAccessException("retry-task : 大于2,抛出远程访问异常"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										58
									
								
								src/main/java/com/qgs/dc/s7/retrydemo/RetryMain.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/main/java/com/qgs/dc/s7/retrydemo/RetryMain.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| package com.qgs.dc.s7.retrydemo; | ||||
|  | ||||
| import org.springframework.remoting.RemoteAccessException; | ||||
| import org.springframework.retry.backoff.FixedBackOffPolicy; | ||||
| import org.springframework.retry.policy.SimpleRetryPolicy; | ||||
| import org.springframework.retry.support.RetryTemplate; | ||||
|  | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
|  | ||||
| public class RetryMain { | ||||
|     public static void main(String[] args) { | ||||
|  | ||||
|         /** | ||||
|          * 重试间隔时间ms,默认1000ms | ||||
|          * */ | ||||
|         long fixedPeriodTime = 1000L; | ||||
|         /** | ||||
|          * 最大重试次数,默认为3 | ||||
|          */ | ||||
|         int maxRetryTimes = 3; | ||||
|         /** | ||||
|          * 表示哪些异常需要重试,key表示异常的字节码,value为true表示需要重试 | ||||
|          */ | ||||
|         Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>(); | ||||
|  | ||||
|  | ||||
|         exceptionMap.put(RemoteAccessException.class,true); | ||||
|  | ||||
|         // 构建重试模板实例 | ||||
|         RetryTemplate retryTemplate = new RetryTemplate(); | ||||
|  | ||||
|         // 设置重试回退操作策略,主要设置重试间隔时间 | ||||
|         FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy(); | ||||
|         backOffPolicy.setBackOffPeriod(fixedPeriodTime); | ||||
|  | ||||
|         // 设置重试策略,主要设置重试次数 | ||||
|         SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(maxRetryTimes, exceptionMap); | ||||
|  | ||||
|         retryTemplate.setRetryPolicy(retryPolicy); | ||||
|         retryTemplate.setBackOffPolicy(backOffPolicy); | ||||
|  | ||||
|         Boolean execute = retryTemplate.execute( | ||||
|                 //RetryCallback | ||||
|                 retryContext -> { | ||||
|                     boolean b = RetryDemoTask.retryTask("abc"); | ||||
|                     System.err.println("retry-main : 调用的结果:"+b+",times:"+retryContext.getRetryCount()); | ||||
|                     return b; | ||||
|                 }, | ||||
|                 retryContext -> { | ||||
|                     //RecoveryCallback | ||||
|                     System.err.println("retry-main : 已达到最大重试次数或抛出了不重试的异常~~~"); | ||||
|                     return false; | ||||
|                 } | ||||
|         ); | ||||
|         System.err.println("retry-main : 执行结果:"+execute); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,66 @@ | ||||
| package com.qgs.dc.s7.retrydemo; | ||||
|  | ||||
| import org.junit.Test; | ||||
| import org.springframework.remoting.RemoteAccessException; | ||||
| import org.springframework.retry.backoff.FixedBackOffPolicy; | ||||
| import org.springframework.retry.policy.SimpleRetryPolicy; | ||||
| import org.springframework.retry.support.RetryTemplate; | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * @Author: zgd | ||||
|  * @Description: spring-retry 重试框架 | ||||
|  */ | ||||
| public class SpringS7RetryTemplateTest { | ||||
|  | ||||
|     /** | ||||
|      * 重试间隔时间ms,默认1000ms | ||||
|      * */ | ||||
|     private long fixedPeriodTime = 1000L; | ||||
|     /** | ||||
|      * 最大重试次数,默认为3 | ||||
|      */ | ||||
|     private int maxRetryTimes = 3; | ||||
|     /** | ||||
|      * 表示哪些异常需要重试,key表示异常的字节码,value为true表示需要重试 | ||||
|      */ | ||||
|     private Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>(); | ||||
|  | ||||
|  | ||||
|     @Test | ||||
|     public void test() { | ||||
|  | ||||
|         //文档:https://blog.csdn.net/minghao0508/article/details/123972703 | ||||
|         exceptionMap.put(RemoteAccessException.class,true); | ||||
|  | ||||
|         // 构建重试模板实例 | ||||
|         RetryTemplate retryTemplate = new RetryTemplate(); | ||||
|  | ||||
|         // 设置重试回退操作策略,主要设置重试间隔时间 | ||||
|         FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy(); | ||||
|         backOffPolicy.setBackOffPeriod(fixedPeriodTime); | ||||
|  | ||||
|         // 设置重试策略,主要设置重试次数 | ||||
|         SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(maxRetryTimes, exceptionMap); | ||||
|  | ||||
|         retryTemplate.setRetryPolicy(retryPolicy); | ||||
|         retryTemplate.setBackOffPolicy(backOffPolicy); | ||||
|  | ||||
|         Boolean execute = retryTemplate.execute( | ||||
|                 //RetryCallback | ||||
|                 retryContext -> { | ||||
|                     boolean b = RetryDemoTask.retryTask("abc"); | ||||
|                     System.out.println("调用的结果:"+b); | ||||
|                     return b; | ||||
|                 }, | ||||
|                 retryContext -> { | ||||
|                     //RecoveryCallback | ||||
|                     System.out.println("已达到最大重试次数或抛出了不重试的异常~~~"); | ||||
|                     return false; | ||||
|                 } | ||||
|         ); | ||||
|         System.out.println("执行结果:"+execute); | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										20
									
								
								src/main/java/com/qgs/dc/s7/retrydemo/TestMain.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/main/java/com/qgs/dc/s7/retrydemo/TestMain.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| package com.qgs.dc.s7.retrydemo; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| public class TestMain { | ||||
|     public static void main(String[] args) { | ||||
|         Integer a = 1; | ||||
|         Integer a1 = 2; | ||||
|         Integer a2 = 3; | ||||
|         List<Integer> list = new ArrayList<Integer>(); | ||||
|         list.add(a); | ||||
|         list.add(a1); | ||||
|         list.add(a2); | ||||
|         Integer integer = list.get(0); | ||||
|         list.remove(integer); | ||||
|         System.out.println(); | ||||
|  | ||||
|     } | ||||
| } | ||||
		Viittaa uudesa ongelmassa
	
	Block a user