commit a9b54f58d6cacb8449f2eafd0f472e37f5db0821 Author: cheney Date: Tue Apr 21 09:19:16 2026 +0800 功能正确 diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..10b731c --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..6c5ad07 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..0cf050b --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..132404b --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..bc20acd --- /dev/null +++ b/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + + com.sunyard + gmapi + 1.0-SNAPSHOT + + + 1.8 + 1.8 + UTF-8 + + + + + + + + gmapi + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.0 + + + + com.sunyard.TestGmApi + + + + + + + \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..63ed896 --- /dev/null +++ b/readme.md @@ -0,0 +1,8 @@ +# 接口 +功能:将符合 ASN1 的请求包发送给待测服务器,并接收响应。实现类自行解决连接的创建和管理。ip 和端在配置文件中配置。 +TCP send/recv 协议:2字节len + 8字节0 + 2字节type + asn1Req +其中 len 为后续所有字节的长度 +其中 type 为 asn1Req 按 asn1 解析后 seq 中第二个字段。seq 中第一个字段是 int 类型的 version +类:com.sunyard.GmApi +返回:byte[] 响应包,recv 包的 asn1Resp 字段 +接口原型:public static byte[] senMsg(byte[] asn1Req) diff --git a/settings.xml b/settings.xml new file mode 100644 index 0000000..e44b44d --- /dev/null +++ b/settings.xml @@ -0,0 +1,24 @@ + + + + + + + + + + alimaven + aliyun maven + https://maven.aliyun.com/repository/public + central + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/sunyard/GmApi.java b/src/main/java/com/sunyard/GmApi.java new file mode 100644 index 0000000..8337429 --- /dev/null +++ b/src/main/java/com/sunyard/GmApi.java @@ -0,0 +1,197 @@ +package com.sunyard; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.Properties; + +public class GmApi { + private static String serverIp; + private static int serverPort; + + private static void loadConfig() { + try { + Properties props = new Properties(); + // Get current jar directory path + String jarPath = GmApi.class.getProtectionDomain().getCodeSource().getLocation().getPath(); + String configPath = new File(jarPath).getParent() + File.separator + "sunyard.properties"; + + // Try to load config file from jar directory + File configFile = new File(configPath); + if (configFile.exists()) { + props.load(new FileInputStream(configFile)); + System.out.println("Config loaded from: " + configPath); + } else { + // If config file not found, use default values + System.out.println("Config file not found, using default: IP=127.0.0.1, Port=8080"); + } + + serverIp = props.getProperty("server.ip", "127.0.0.1"); + serverPort = Integer.parseInt(props.getProperty("server.port", "8080")); + System.out.println("Config loaded: IP=" + serverIp + ", Port=" + serverPort); + } catch (Exception e) { + System.out.println("Failed to load config, using default: IP=127.0.0.1, Port=8080"); + e.printStackTrace(); + serverIp = "127.0.0.1"; + serverPort = 8080; + } + } + + public static byte[] sendMsg(byte[] asn1Req) { + // Reload config file every time sending message + loadConfig(); + System.out.println("Start sending message, request length: " + asn1Req.length); + + // Parse ASN1 request to get type field + int type = parseTypeFromAsn1(asn1Req); + System.out.println("Parsed ASN1 type: " + type); + + Socket socket = null; + DataOutputStream dos = null; + DataInputStream dis = null; + + try { + // Create connection with timeout + System.out.println("Connecting to server: " + serverIp + ":" + serverPort); + socket = new Socket(); + socket.connect(new InetSocketAddress(serverIp, serverPort), 5000); // 5s connection timeout + socket.setSoTimeout(5000); // 5s read timeout + + // Calculate total length + int totalLength = 8 + 2 + asn1Req.length; + System.out.println("Calculated total length: " + totalLength); + + // Build send data + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dataOut = new DataOutputStream(baos); + + // Write 2 bytes len + dataOut.writeShort(totalLength); + // Write 8 bytes 0 + for (int i = 0; i < 8; i++) { + dataOut.writeByte(0); + } + // Write 2 bytes type + dataOut.writeShort(type); + // Write asn1Req + dataOut.write(asn1Req); + + byte[] sendData = baos.toByteArray(); + System.out.println("Send data length: " + sendData.length); + System.out.println("Send data hex: " + bytesToHex(sendData)); + + // Send data + dos = new DataOutputStream(socket.getOutputStream()); + dos.write(sendData); + dos.flush(); + System.out.println("Data sent successfully"); + + // Receive response + dis = new DataInputStream(socket.getInputStream()); + + // Read response length + int respLength = dis.readUnsignedShort(); + System.out.println("Received response length: " + respLength); + + // Read 8 bytes 0 + byte[] zeros = new byte[8]; + dis.readFully(zeros); + + // Read 2 bytes type + int respType = dis.readUnsignedShort(); + System.out.println("Received response type: " + respType); + + // Read asn1Resp + byte[] asn1Resp = new byte[respLength - 8 - 2]; + dis.readFully(asn1Resp); + System.out.println("Received asn1Resp length: " + asn1Resp.length); + + return asn1Resp; + + } catch (Exception e) { + System.out.println("Failed to send message"); + e.printStackTrace(); + return null; + } finally { + // Close resources + try { + if (dis != null) dis.close(); + if (dos != null) dos.close(); + if (socket != null) socket.close(); + System.out.println("Connection closed"); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public static String bytesToHex(byte[] bytes) { + if (bytes == null || bytes.length == 0) { + return ""; + } + StringBuilder sb = new StringBuilder(bytes.length * 2); + for (byte b : bytes) { + // 将 byte 转为无符号整数(0~255) + int val = b & 0xFF; + // 转为两位十六进制,不足两位补零 + sb.append(String.format("%02x", val)); + } + return sb.toString(); + } + + private static int parseTypeFromAsn1(byte[] asn1Data) { + try { + ByteArrayInputStream bais = new ByteArrayInputStream(asn1Data); + DataInputStream dis = new DataInputStream(bais); + + // Skip seq header + int seqTag = dis.read(); + int seqLength = readAsn1Length(dis); // 使用正确的长度读取方法 + System.out.println("ASN1 seq tag: " + seqTag + ", length: " + seqLength); + + // Skip first field (version, int type) + int versionTag = dis.read(); + int versionLength = readAsn1Length(dis); + dis.skip(versionLength); + System.out.println("Skipped version field: tag=" + versionTag + ", length=" + versionLength); + + // Read second field (type) + int typeTag = dis.read(); + int typeLength = readAsn1Length(dis); + int type = 0; + for (int i = 0; i < typeLength; i++) { + type = (type << 8) | (dis.read() & 0xFF); + } + + dis.close(); + return type; + + } catch (Exception e) { + System.out.println("Failed to parse ASN1"); + e.printStackTrace(); + return 0; + } + } + + private static int readAsn1Length(DataInputStream dis) throws IOException { + int length = dis.read(); + if (length < 128) { + // 短形式:直接返回长度值 + return length; + } else { + // 长形式:计算后续长度字节的数量 + int numBytes = length & 0x7F; + length = 0; + for (int i = 0; i < numBytes; i++) { + length = (length << 8) | (dis.read() & 0xFF); + } + return length; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/sunyard/TestGmApi.java b/src/main/java/com/sunyard/TestGmApi.java new file mode 100644 index 0000000..af98a22 --- /dev/null +++ b/src/main/java/com/sunyard/TestGmApi.java @@ -0,0 +1,62 @@ +package com.sunyard; + +public class TestGmApi { + public static void main(String[] args) { + // Mock ASN1 request data in hex format +// String hexAsn1Req = "30 82 01 35 " + +// "02 01 01 02 01 03 30 82 01 1A 02 03 02 02 01 02 " + +// "01 29 04 08 31 32 33 34 35 36 37 38 02 02 01 00 " + +// "04 82 01 00 00 01 02 03 04 05 06 07 08 09 0A 0B " + +// "0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B " + +// "0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B " + +// "0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B " + +// "0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B " + +// "0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B " + +// "0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B " + +// "0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B " + +// "0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B " + +// "0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B " + +// "0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B " + +// "0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B " + +// "0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B " + +// "0C 0D 0E 0F 00 01 02 03 04 05 06 07 08 09 0A 0B " + +// "0C 0D 0E 0F 18 0F 32 30 32 36 30 33 30 34 30 36 " + +// "30 30 33 36 5A"; +// +// // Convert hex string to byte array +// byte[] asn1Req = hexStringToByteArray(hexAsn1Req); + + byte[] asn1Req = new byte[]{48, 56, 2, 1, 0, 2, 1, 0, -96, 31, 4, 29, 67, 61, 99, 110, 44, 79, 61, 73, 78, 70, 79, 83, 69, 67, 44, 67, 78, 61, 115, 109, 50, 95, 110, 101, 116, 115, 105, 103, 110, 24, 15, 50, 48, 50, 54, 48, 52, 48, 56, 48, 57, 49, 48, 52, 48, 90}; + + System.out.println("Testing GmApi.sendMsg method"); + System.out.println("ASN1 request length: " + asn1Req.length); + byte[] response = GmApi.sendMsg(asn1Req); + + if (response != null) { + System.out.println("Response successful, response length: " + response.length); + } else { + System.out.println("Response failed"); + } + } + + private static byte[] hexStringToByteArray(String hexString) { + // Remove spaces and newlines + hexString = hexString.replaceAll("\\s+", ""); + + // Check if the length is even + if (hexString.length() % 2 != 0) { + throw new IllegalArgumentException("Hex string length must be even"); + } + + byte[] result = new byte[hexString.length() / 2]; + + for (int i = 0; i < hexString.length(); i += 2) { + String hexByte = hexString.substring(i, i + 2); + result[i / 2] = (byte) Integer.parseInt(hexByte, 16); + } + + return result; + } + + +} \ No newline at end of file diff --git a/sunyard.properties b/sunyard.properties new file mode 100644 index 0000000..637c78f --- /dev/null +++ b/sunyard.properties @@ -0,0 +1,2 @@ +server.ip=127.0.0.1 +server.port=8080 diff --git a/target/classes/com/sunyard/GmApi.class b/target/classes/com/sunyard/GmApi.class new file mode 100644 index 0000000..4af23e2 Binary files /dev/null and b/target/classes/com/sunyard/GmApi.class differ diff --git a/target/classes/com/sunyard/TestGmApi.class b/target/classes/com/sunyard/TestGmApi.class new file mode 100644 index 0000000..c1f2098 Binary files /dev/null and b/target/classes/com/sunyard/TestGmApi.class differ diff --git a/target/gmapi.jar b/target/gmapi.jar new file mode 100644 index 0000000..dd01030 Binary files /dev/null and b/target/gmapi.jar differ diff --git a/target/maven-archiver/pom.properties b/target/maven-archiver/pom.properties new file mode 100644 index 0000000..952a344 --- /dev/null +++ b/target/maven-archiver/pom.properties @@ -0,0 +1,3 @@ +artifactId=gmapi +groupId=com.sunyard +version=1.0-SNAPSHOT diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..9919388 --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1,2 @@ +com\sunyard\TestGmApi.class +com\sunyard\GmApi.class diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..e9cb3cc --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,2 @@ +D:\workbench\gmapi\src\main\java\com\sunyard\TestGmApi.java +D:\workbench\gmapi\src\main\java\com\sunyard\GmApi.java