功能正确

This commit is contained in:
cheney
2026-04-21 09:19:16 +08:00
commit a9b54f58d6
18 changed files with 432 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="gmapi" />
</profile>
</annotationProcessing>
</component>
</project>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>
+40
View File
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="http://nexus.honor3.com:8081/repository/maven-public" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="http://nexus.honor3.com/repository/maven-public" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="nexus-own" />
<option name="name" value="nexus-own" />
<option name="url" value="http://nexus.honor3.com:8081/repository/maven-public" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="nexus-own" />
<option name="name" value="nexus-own" />
<option name="url" value="http://nexus.honor3.com/repository/maven-public" />
</remote-repository>
</component>
</project>
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
+47
View File
@@ -0,0 +1,47 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sunyard</groupId>
<artifactId>gmapi</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- 这里可以添加项目依赖 -->
</dependencies>
<build>
<finalName>gmapi</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.sunyard.TestGmApi</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
+8
View File
@@ -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)
+24
View File
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<proxies>
</proxies>
<servers>
</servers>
<mirrors>
<!--阿里云镜像-->
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>https://maven.aliyun.com/repository/public</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
<pluginGroups>
</pluginGroups>
<profiles>
</profiles>
<activeProfiles>
</activeProfiles>
</settings>
+197
View File
@@ -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;
}
}
}
+62
View File
@@ -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;
}
}
+2
View File
@@ -0,0 +1,2 @@
server.ip=127.0.0.1
server.port=8080
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
+3
View File
@@ -0,0 +1,3 @@
artifactId=gmapi
groupId=com.sunyard
version=1.0-SNAPSHOT
@@ -0,0 +1,2 @@
com\sunyard\TestGmApi.class
com\sunyard\GmApi.class
@@ -0,0 +1,2 @@
D:\workbench\gmapi\src\main\java\com\sunyard\TestGmApi.java
D:\workbench\gmapi\src\main\java\com\sunyard\GmApi.java