java实现TCP客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Arrays;

public class TcpClientUtil {
private static final String SERVER_ADDRESS = "192.19.28.211"; // 替换为目标服务器地址
private static final int SERVER_PORT = 4001; // 替换为目标服务器端口
private static final String ADDREES = "01030065000315D4"; // 替换为目标服务器端口

public static void main(String[] args) {
byte[] request = hexStringToByteArray("01030065000315D4");

try (Socket socket = new Socket(SERVER_ADDRESS, SERVER_PORT)) {
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();

// 发送请求
out.write(request);
out.flush();

// 接收响应
byte[] response = new byte[1024];
int bytesRead = in.read(response);

// 打印接收到的响应(十六进制)
if (bytesRead != -1) {
byte[] actualResponse = Arrays.copyOf(response, bytesRead);
String hexResponse = byteArrayToHexString(actualResponse);
System.out.println("响应: " + hexResponse);

// 解析响应
parseResponse(actualResponse);
}

} catch (Exception e) {
e.printStackTrace();
}
}

// 将十六进制字符串转换为字节数组
private static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}

// 将字节数组转换为十六进制字符串
private static String byteArrayToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X", b));
}
return sb.toString();
}

// 解析响应
private static void parseResponse(byte[] response) {
if (response.length < 5) {
System.out.println("响应数据无效");
return;
}

// 提取数据
byte deviceAddress = response[0];
byte functionCode = response[1];
byte dataLength = response[2];
byte[] data = Arrays.copyOfRange(response, 3, 3 + dataLength);
byte[] crc = Arrays.copyOfRange(response, 3 + dataLength, 3 + dataLength + 2);

// 打印解析结果
System.out.println("设备地址: " + String.format("%02X", deviceAddress));
System.out.println("功能码: " + String.format("%02X", functionCode));
System.out.println("数据长度: " + String.format("%02X", dataLength));
System.out.println("数据: " + byteArrayToHexString(data));
System.out.println("CRC校验和: " + byteArrayToHexString(crc));

// 解析具体数据
for (int i = 0; i < data.length; i += 2) {
int value = ((data[i] & 0xFF) << 8) | (data[i + 1] & 0xFF);
System.out.println(String.format("寄存器 %d: %04X (%d)", i / 2, value, value));
}
}
}

CRC16Modbus 校验码生成

低位在前

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import java.util.Arrays;

public class CRC16Modbus {
// Precomputed CRC table for faster calculation
private static final int[] CRC_TABLE = new int[256];

static {
for (int i = 0; i < 256; i++) {
int crc = i;
for (int j = 8; j > 0; j--) {
if ((crc & 1) != 0) {
crc = (crc >>> 1) ^ 0xA001;
} else {
crc >>>= 1;
}
}
CRC_TABLE[i] = crc;
}
}

public static byte[] calculateCRC(byte[] data) {
int crc = 0xFFFF; // Initial value

for (byte b : data) {
crc = (crc >>> 8) ^ CRC_TABLE[(crc ^ b) & 0xFF];
}

// Swap the bytes for Modbus
byte crcLow = (byte) (crc & 0xFF);
byte crcHigh = (byte) ((crc >>> 8) & 0xFF);

return new byte[]{crcLow, crcHigh};
}

public static void main(String[] args) {
byte[] data = {0x01, 0x03, 0x00, 0x65, 0x00, 0x05}; // Example data
byte[] crc = calculateCRC(data);
String hexString = ByteArrayToHexString(data);
String format = String.format("%02X%02X%n", crc[0], crc[1]);
System.out.println(hexString + format);

byte[] data3 = {0x01, 0x03, 0x00, 0x65, 0x00, 0x03, 0x15, (byte) 0xD4};
}


public static String ByteArrayToHexString(byte[] data) {
StringBuilder hexString = new StringBuilder();
for (byte b : data) {
hexString.append(String.format("%02X", b));
}
return hexString.toString();
}


// 解析响应
private static void parseResponse(byte[] response) {
if (response.length < 5) {
System.out.println("响应数据无效");
return;
}

// 提取数据
byte deviceAddress = response[0];
byte functionCode = response[1];
byte dataLength = response[2];
byte[] data = Arrays.copyOfRange(response, 3, 3 + dataLength);
byte[] crc = Arrays.copyOfRange(response, 3 + dataLength, 3 + dataLength + 2);

// 打印解析结果
System.out.println("设备地址: " + String.format("%02X", deviceAddress));
System.out.println("功能码: " + String.format("%02X", functionCode));
System.out.println("数据长度: " + String.format("%02X", dataLength));
System.out.println("数据: " + byteArrayToHexString(data));
System.out.println("CRC校验和: " + byteArrayToHexString(crc));
}


// 将十六进制字符串转换为字节数组
private static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}

// 将字节数组转换为十六进制字符串
private static String byteArrayToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X", b));
}
return sb.toString();
}
}

高位在前

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class CRC16Modbus {
// Precomputed CRC table for faster calculation
private static final int[] CRC_TABLE = new int[256];

static {
for (int i = 0; i < 256; i++) {
int crc = i;
for (int j = 8; j > 0; j--) {
if ((crc & 1) != 0) {
crc = (crc >>> 1) ^ 0xA001;
} else {
crc >>>= 1;
}
}
CRC_TABLE[i] = crc;
}
}

public static int calculateCRC(byte[] data) {
int crc = 0xFFFF; // Initial value

for (byte b : data) {
crc = (crc >>> 8) ^ CRC_TABLE[(crc ^ b) & 0xFF];
}

// Swap the bytes for Modbus
crc = (crc << 8) | ((crc >>> 8) & 0xFF);

return crc & 0xFFFF; // Return as 16-bit value
}

public static void main(String[] args) {
byte[] data = {0x01, 0x03, 0x00, 0x00, 0x00, 0x0A}; // Example data
int crc = calculateCRC(data);
System.out.printf("CRC16 Modbus: 0x%04X%n", crc);
}
}

解析 01030600D1010E00357D4F

解析响应 01030600D1010E00357D4F 的示例代码如下:

解释响应

  • 设备地址: 01
  • 功能码: 03
  • 数据长度: 06
  • 数据: 00D1, 010E, 0035
  • CRC校验和: 7D4F

我们将这些部分提取并打印出来。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Arrays;

public class TcpClient {
private static final String SERVER_ADDRESS = "127.0.0.1"; // 替换为目标服务器地址
private static final int SERVER_PORT = 502; // 替换为目标服务器端口

public static void main(String[] args) {
byte[] request = hexStringToByteArray("01030065000595D6");

try (Socket socket = new Socket(SERVER_ADDRESS, SERVER_PORT)) {
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();

// 发送请求
out.write(request);
out.flush();

// 接收响应
byte[] response = new byte[1024];
int bytesRead = in.read(response);

// 打印接收到的响应(十六进制)
if (bytesRead != -1) {
byte[] actualResponse = Arrays.copyOf(response, bytesRead);
String hexResponse = byteArrayToHexString(actualResponse);
System.out.println("响应: " + hexResponse);

// 解析响应
parseResponse(actualResponse);
}

} catch (Exception e) {
e.printStackTrace();
}
}

// 将十六进制字符串转换为字节数组
private static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}

// 将字节数组转换为十六进制字符串
private static String byteArrayToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X", b));
}
return sb.toString();
}

// 解析响应
private static void parseResponse(byte[] response) {
if (response.length < 5) {
System.out.println("响应数据无效");
return;
}

// 提取数据
byte deviceAddress = response[0];
byte functionCode = response[1];
byte dataLength = response[2];
byte[] data = Arrays.copyOfRange(response, 3, 3 + dataLength);
byte[] crc = Arrays.copyOfRange(response, 3 + dataLength, 3 + dataLength + 2);

// 打印解析结果
System.out.println("设备地址: " + String.format("%02X", deviceAddress));
System.out.println("功能码: " + String.format("%02X", functionCode));
System.out.println("数据长度: " + String.format("%02X", dataLength));
System.out.println("数据: " + byteArrayToHexString(data));
System.out.println("CRC校验和: " + byteArrayToHexString(crc));

// 解析具体数据
for (int i = 0; i < data.length; i += 2) {
int value = ((data[i] & 0xFF) << 8) | (data[i + 1] & 0xFF);
System.out.println(String.format("寄存器 %d: %04X (%d)", i / 2, value, value));
}
}
}

解析

  • 设备地址: 01
  • 功能码: 03
  • 数据长度: 06
  • 数据:
    • 第一个寄存器: 00D1 -> 十进制 209
    • 第二个寄存器: 010E -> 十进制 270
    • 第三个寄存器: 0035 -> 十进制 53
  • CRC校验和: 7D4F

运行这个程序将输出解析后的每个部分,并详细解释每个寄存器的值。你可以根据需要进一步处理这些数据。

-------------本文结束感谢您的阅读-------------