功能正确
This commit is contained in:
Generated
+5
@@ -0,0 +1,5 @@
|
|||||||
|
# 默认忽略的文件
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# 基于编辑器的 HTTP 客户端请求
|
||||||
|
/httpRequests/
|
||||||
Generated
+13
@@ -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>
|
||||||
Generated
+7
@@ -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>
|
||||||
Generated
+40
@@ -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>
|
||||||
Generated
+14
@@ -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
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -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)
|
||||||
@@ -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>
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
server.ip=127.0.0.1
|
||||||
|
server.port=8080
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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
|
||||||
Reference in New Issue
Block a user