Browse Source

vds parsing add

shjung 3 years ago
parent
commit
5e81e78268

+ 181 - 57
src/main/java/com/its/op/service/its/vds/VdsControlService.java

@@ -9,10 +9,8 @@ import com.its.utils.ItsUtils;
 import com.its.utils.SysUtils;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.io.FileUtils;
 import org.springframework.stereotype.Service;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -24,6 +22,7 @@ import java.nio.ByteOrder;
 import java.util.Base64;
 import java.util.NoSuchElementException;
 import java.util.Optional;
+import java.util.concurrent.*;
 
 @Slf4j
 @RequiredArgsConstructor
@@ -173,9 +172,9 @@ public class VdsControlService {
      * @return
      */
     public VdsControlDto.VdsControlRes controlReset(String id, VdsControlDto.VdsControlResetReq req) {
-        TbVdsCtlr vds = this.requireOne(id);
+        //TbVdsCtlr vds = this.requireOne(id);
         ByteBuffer cmdBuffer = getCommand((byte)0x0C, 0, Integer.valueOf(id), 0, 0);
-        return requestVdsCommand(cmdBuffer, 0);
+        return requestVdsCommandReset(cmdBuffer);
     }
 
     /**
@@ -185,86 +184,215 @@ public class VdsControlService {
      * @return
      */
     public VdsControlDto.VdsControlRes requestStopImage(String id, VdsControlDto.VdsControlStopImageReq req) {
-        TbVdsCtlr vds = this.requireOne(id);
+        //TbVdsCtlr vds = this.requireOne(id);
         ByteBuffer cmdBuffer = getCommand((byte)0x16, 0, Integer.valueOf(id), req.getFrameNo(), req.getCameraNo());
-        return requestVdsCommand(cmdBuffer, 1);
+        return requestVdsCommandStopImage(cmdBuffer);
     }
 
     /**
-     * VDS 통신서버로 요청 메시지 전송
+     * VDS 통신서버로 RESET 메시지 전송
      * @param cmdBuffer
-     * @param cmdType
      * @return
      */
-    public VdsControlDto.VdsControlRes requestVdsCommand(ByteBuffer cmdBuffer, int cmdType) {
+    public VdsControlDto.VdsControlRes requestVdsCommandReset(ByteBuffer cmdBuffer) {
         VdsControlDto.VdsControlRes result = new VdsControlDto.VdsControlRes(0, "success");
         if (cmdBuffer == null) {
-            result.setResult(2, "VDS 통신 메시지 생성 중 오류가 발생하였습니다.");
+            result.setResult(1, "VDS 통신 메시지 생성 중 오류가 발생하였습니다.");
             return result;
         }
-log.error("xxxxxxxxxxxxxxxxxxxxxxxx");
-        String saveDir = ItsUtils.createUserDir("/image/vds/");
-        //String saveFileName = saveDir + ItsUtils.getSysTime() + ".jpg";
-        String saveFileName = saveDir + "vdsImage" + ".jpg";
-log.error("{}", saveFileName);
+
         String ipAddress = this.vdsServerConfig.getIpAddress();
         int port = this.vdsServerConfig.getPort();
         int connectTimeout = 3000; // milli-seconds
-        int readTimeout = cmdType == 0 ? 2000 : 5000; // milli-seconds
+        int readTimeout = 2000; // milli-seconds
         SocketAddress socketAddress = new InetSocketAddress(ipAddress, port);
         Socket socket = null;
-        if (cmdType == 1) {
-            byte[] fileContent = new byte[0];
-            try {
-                fileContent = FileUtils.readFileToByteArray(new File(saveFileName));
-            } catch (IOException e) {
-                log.error("{}", e.getMessage());
-            }
-            String image = Base64.getEncoder().encodeToString(fileContent);
-            result.setImage(image);
-        }
         try {
             socket = new Socket();
             socket.setSoTimeout(readTimeout);			    /* InputStream 에서 데이터읽을때의 timeout */
             socket.connect(socketAddress, connectTimeout);  /* socket 연결 자체에대한 timeout */
 
-            byte[] data = cmdBuffer.array();
-            OutputStream os = socket.getOutputStream();
-            os.write(data);
-            os.flush();
-
-            // 24 04 01 01 00 70 00 00 00 0d
-            // OpCode: 5
-            // Length: 6 7 8 9
-            InputStream recvStream = socket.getInputStream();
-            boolean loop = true;
-            byte[] buffer = new byte[2048];
-            while (loop) {
-                try {
-                    int recvLen = recvStream.read(buffer, 0, buffer.length);
-                    log.error("recv: {} Bytes.", recvLen);
-                } catch (IOException e) {
-                    log.error("VdsControlService: requestVdsCommand, recvStream.read IOException, {}", e.getMessage());
-                    result.setResult(4, "VDS 서버와 통신로 부터 결과 수신 시간초과가 발생하였습니다.");
-                    loop = false;
-                }
+            try {
+                byte[] data = cmdBuffer.array();
+                OutputStream os = socket.getOutputStream();
+                os.write(data);
+                os.flush();
+                result.setResult(0, "VDS 서버에 제어기 리셋명령을 정상적으로 전송하였습니다.");
+            } catch (IOException e) {
+                result.setResult(3, "VDS 서버에 제어기 리셋명령을 정상적으로 전송하지 못하였습니다.");
             }
-        }
-        catch (IOException e) {
+        } catch (IOException e) {
             log.error("X. {}, {}, {}", ipAddress, port, e.getMessage());
-            result.setResult(3, "VDS 서버와 통신이 실패하였습니다.");
+            String errMsg = "[VDS 서버: " + ipAddress + "." + port + "]";
+            result.setResult(2, "VDS 서버와 통신이 실패하였습니다.\r\n" + errMsg);
             return result;
-        }
-        finally {
+        } finally {
             try {
                 if (socket != null) {
                     socket.close();
                 }
+            } catch (IOException e) {
+                log.error("VdsControlService: requestVdsCommandReset, socket close IOException");
             }
-            catch (IOException e) {
-                log.error("VdsControlService: requestVdsCommand, socket close IOException");
+        }
+        return result;
+    }
+
+    /**
+     * VDS 통신서버로 요청 메시지 전송
+     * @param cmdBuffer
+     * @return
+     */
+    public VdsControlDto.VdsControlRes requestVdsCommandStopImage(ByteBuffer cmdBuffer) {
+
+        VdsControlDto.VdsControlRes result = new VdsControlDto.VdsControlRes(0, "success");
+        if (cmdBuffer == null) {
+            result.setResult(1, "VDS 통신 메시지 생성 중 오류가 발생하였습니다.");
+            return result;
+        }
+
+        String saveDir = ItsUtils.createUserDir("/image/vds/");
+        //String saveFileName = saveDir + ItsUtils.getSysTime() + ".jpg";
+        String saveFileName = saveDir + "vdsImage" + ".jpg";
+        log.error("{}", saveFileName);
+        String ipAddress = this.vdsServerConfig.getIpAddress();
+        int port = this.vdsServerConfig.getPort();
+        int taskTimeout = 6000; // milli-seconds
+        int connectTimeout = 3000; // milli-seconds
+        int readTimeout = 4000; // milli-seconds
+
+        ExecutorService executorService = Executors.newSingleThreadExecutor();
+        Callable<Integer> task = new Callable<Integer>() {
+            @Override
+            public Integer call() throws Exception {
+                int taskResult = 0;
+                SocketAddress socketAddress = new InetSocketAddress(ipAddress, port);
+                Socket socket = null;
+
+//                byte[] fileContent = new byte[0];
+//                try {
+//                    fileContent = FileUtils.readFileToByteArray(new File(saveFileName));
+//                } catch (IOException e) {
+//                    log.error("{}", e.getMessage());
+//                }
+//                String image = Base64.getEncoder().encodeToString(fileContent);
+//                result.setImage(image);
+
+                try {
+                    socket = new Socket();
+                    socket.setSoTimeout(readTimeout);			    /* InputStream 에서 데이터읽을때의 timeout */
+                    socket.connect(socketAddress, connectTimeout);  /* socket 연결 자체에대한 timeout */
+
+                    try {
+                        byte[] data = cmdBuffer.array();
+                        OutputStream os = socket.getOutputStream();
+                        os.write(data);
+                        os.flush();
+                    } catch (IOException e) {
+                        taskResult = 3;
+                        result.setResult(taskResult, "VDS 서버에 정지영상 요청 명령을 정상적으로 전송하지 못하였습니다.");
+                    }
+                    if (taskResult != 0) {
+                        return taskResult;
+                    }
+
+                    // 24 04 01 01 00 70 00 00 00 0d ==> ACK 메시지
+                    // OpCode: 5
+                    // Length: 6 7 8 9
+                    // 00 00 00 00 00 16 00 00 00 00 ==> 이미지정보 수신 헤더.....+ N
+                    // 24 04 01 01 00 16 00 00 00 00 ==> 이미지정보 수신후 마지막 패킷
+                    InputStream recvStream = socket.getInputStream();
+
+                    // Read Frame Head
+                    while (true) {
+                        // 이미지 헤더를 읽을 때 까지 헤더 크기 만큼 데이터 수신
+                        // 상태 정보(ACK) 등이 수신될수 있다.
+                        byte[] head = receiveBytes(recvStream, 10);
+                        if (head[0] == (byte) 0x00 && head[1] == (byte) 0x00 && head[5] == (byte) 0x16) {
+                            int imageHeaderRemainLength = 172;  // 이미지 헤더 사이즈 만큼 더 읽어야 함
+                            byte[] imageHead = receiveBytes(recvStream, imageHeaderRemainLength);
+                            int imageSize = SysUtils.bytesToInt(imageHead, 159, ByteOrder.BIG_ENDIAN);
+                            if (imageSize > 0) {
+                                // 이미지 사이즈 만큼 이미지 데이터를 읽어온다.
+                                byte[] image = receiveBytes(recvStream, imageSize);
+                                String imageString = Base64.getEncoder().encodeToString(image);
+                                result.setImage(imageString);
+                                result.setResult(0, "VDS 서버로 부터 정지영상 이미지를 정상적으로 수신하였습니다.");
+                            } else {
+                                result.setResult(99, "VDS 서버로 부터 수신한 이미지가 정상적이지 않습니다.");
+                            }
+                            break;
+                        } else {
+                            int dataSize = SysUtils.bytesToInt(head, 6, ByteOrder.BIG_ENDIAN);
+                            log.info("RECV HEAD: {} Data Bytes Remain. {}", dataSize, SysUtils.byteArrayToHex(head));
+                            if (dataSize > 0) {
+                                byte[] data = receiveBytes(recvStream, dataSize);
+                                log.info("RECV DATA: {} Data Bytes. {}", dataSize, SysUtils.byteArrayToHex(data));
+                            }
+                        }
+                    }
+                } catch (IOException e) {
+                    log.error("X. {}, {}, {}", ipAddress, port, e.getMessage());
+                    String errMsg = "[VDS 서버: " + ipAddress + "." + port + "]";
+                    taskResult = 2;
+                    result.setResult(taskResult, "VDS 서버와 통신이 실패하였습니다.\r\n" + errMsg);
+                } finally {
+                    try {
+                        if (socket != null) {
+                            socket.close();
+                        }
+                    } catch (IOException e) {
+                        log.error("VdsControlService: requestVdsCommandReset, socket close IOException");
+                    }
+                }
+                return taskResult;
+            }
+        };
+
+        Future<Integer> future = executorService.submit(task);
+        try {
+            Integer taskResult = future.get(taskTimeout, TimeUnit.MILLISECONDS);
+            if (taskResult == 0) {
+            }
+        } catch (InterruptedException e) {
+            result.setResult(5, "VDS 정지영상 요청 작업 중 인터럽트가 발생하여 작업이 실패하였습니다.");
+        } catch (ExecutionException e) {
+            result.setResult(6, "VDS 정지영상 요청 작업 스레드를 생성하지 못하여 작업이 실패하였습니다.");
+        } catch (TimeoutException e) {
+            // timeout 발생시 진입하는 catch 문
+            result.setResult(7, "VDS 정지영상 요청 작업이 시간초과 되어 작업이 실패하였습니다.");
+        } finally {
+            executorService.shutdown();
+        }
+        log.error("requestVdsCommandStopImage: {}, {}", result.getError(), result.getMessage());
+        return result;
+    }
+
+    /**
+     * 소켓 입력 버퍼로 부터 데이터 길이만큼 읽어 온다
+     * @param inStream
+     * @param buffSize
+     * @return
+     * @throws IOException
+     */
+    public byte[] receiveBytes(InputStream inStream, int buffSize) throws IOException {
+        byte[] buffer;
+        int bytesRead = 0;
+        int readThisTime = 0;
+        buffer = new byte[buffSize];
+        while (bytesRead < buffSize)
+        {
+            readThisTime = inStream.read(buffer, bytesRead, buffSize - bytesRead);
+            if (readThisTime == -1)
+            {
+                throw new IOException("Socket.receive(): Socket closed unexpectedly");
             }
+            bytesRead += readThisTime;
         }
+        return buffer;
+    }
+}
+
 //
 //        Channel channel = this.vdsCommClientService.getVdsClient().getChannel();
 //        if (channel == null || !channel.isActive()) {
@@ -278,7 +406,3 @@ log.error("{}", saveFileName);
 //        } else {
 //            result.setResult(4, "VDS 서버에 요청 메시지 전송이 실패하였습니다.");
 //        }
-
-        return result;
-    }
-}

+ 29 - 2
src/main/java/com/its/utils/SysUtils.java

@@ -2,6 +2,8 @@ package com.its.utils;
 
 import lombok.extern.slf4j.Slf4j;
 
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Date;
@@ -97,8 +99,7 @@ public final class SysUtils
 	}
 
 	public static byte[] stringToByteArray(String data) {
-		byte[] byteData = data.getBytes();
-		return byteData;
+		return data.getBytes();
 	}
 	public static void copyStringToByteArray(byte[] dest, int length, String data) {
 		byte[] byteData = data.getBytes();
@@ -214,4 +215,30 @@ public final class SysUtils
 		}
 		return sb.toString();
 	}
+
+	public static int bytesToInt(byte[] bytes) {
+		return ByteBuffer.wrap(bytes).getInt();
+	}
+	public static int bytesToInt(byte[] bytes, int fromIdx, ByteOrder byteOrder) {
+
+		if (byteOrder == ByteOrder.BIG_ENDIAN) {
+			return (
+				((bytes[fromIdx+0] & 0xFF) << 24) |
+				((bytes[fromIdx+1] & 0xFF) << 16) |
+				((bytes[fromIdx+2] & 0xFF) << 8 ) |
+				((bytes[fromIdx+3] & 0xFF) << 0 )
+			);
+		}
+		return (
+			((bytes[fromIdx+3] & 0xFF) << 24) |
+			((bytes[fromIdx+2] & 0xFF) << 16) |
+			((bytes[fromIdx+1] & 0xFF) << 8 ) |
+			((bytes[fromIdx+0] & 0xFF) << 0 )
+		);
+	}
+
+	public static byte[] intToBytes(int value) {
+		// BIG_ENDIAN
+		return  ByteBuffer.allocate(4).putInt(value).array();
+	}
 }