package com.ruoyi.fuzhou.utils.oilmodbus;
|
|
import com.alibaba.fastjson2.JSONObject;
|
import com.ruoyi.fuzhou.domain.ReceiveOilInfo;
|
import com.ruoyi.fuzhou.enums.DataTypeEnum;
|
|
import java.io.IOException;
|
import java.io.InputStream;
|
import java.io.OutputStream;
|
import java.net.ServerSocket;
|
import java.net.Socket;
|
import java.nio.ByteBuffer;
|
import java.nio.ByteOrder;
|
import java.util.List;
|
|
public class ModbusOilServerUtils {
|
public static void main(String[] args) {
|
//
|
// //质量流量
|
String value = getValue("0.0.0.0", 8140, (byte) 0x05, (byte) 0x04, 167, 0x0002, 1);
|
// //利和油设备
|
// String value = getValue("0.0.0.0", 8247, (byte) 1, (byte) 3, 13, 2, 12);
|
System.out.println(value);
|
}
|
/**
|
* @param ip ip
|
* @param port 端口
|
* @param list 查询项列表
|
*/
|
public static JSONObject getValue(String ip, int port, List<ReceiveOilInfo> list) {
|
// 服务端配置
|
String SERVER_IP = ip; // 监听所有网络接口
|
int SERVER_PORT = port; // 端口号
|
ServerSocket serverSocket = null;
|
try {
|
serverSocket = new ServerSocket(SERVER_PORT);
|
System.out.println("🛡️ 服务端已启动,正在监听 " + SERVER_IP + ":" + SERVER_PORT + "...");
|
serverSocket.setSoTimeout(4000);
|
Socket clientSocket = serverSocket.accept();
|
System.out.println("🔌 客户端已连接: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
|
try (InputStream inputStream = clientSocket.getInputStream();
|
OutputStream outputStream = clientSocket.getOutputStream()) {
|
JSONObject jsonObject = new JSONObject();
|
for (ReceiveOilInfo info : list
|
) {
|
// 构造请求帧
|
ByteBuffer requestBuffer = ByteBuffer.allocate(8);
|
if (info.getDeviceAddress() != 0) {
|
requestBuffer.put(info.getDeviceAddress()); // 设备地址
|
}
|
if (info.getFunctionCode() != 0) {
|
requestBuffer.put(info.getFunctionCode()); // 功能码
|
}
|
if (info.getRegisterAdress() != 0) {
|
requestBuffer.putShort((short) info.getRegisterAdress().intValue()); // 寄存器地址
|
}
|
if (info.getRegisterCount() != 0) {
|
requestBuffer.putShort((short) info.getRegisterCount().intValue()); // 寄存器数量
|
}
|
// 计算CRC校验码
|
byte[] requestData = requestBuffer.array();
|
String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
|
int decimal = Integer.parseInt(hex, 16);
|
requestBuffer.putShort((short) decimal); // CRC校验码
|
// 发送请求帧
|
outputStream.write(requestBuffer.array());
|
System.out.println("📤 已发送 MODBUS 请求: " + bytesToHex(requestBuffer.array()));
|
// 接收设备响应
|
byte[] response = new byte[1024];
|
int bytesRead = inputStream.read(response);
|
if (bytesRead == -1) {
|
System.out.println("❌ 未收到设备响应");
|
continue;
|
}
|
// 打印响应数据
|
byte[] responseData = new byte[bytesRead];
|
System.arraycopy(response, 0, responseData, 0, bytesRead);
|
String resultData = bytesToHex(responseData);
|
System.out.println("📥 收到设备响应: " + resultData);
|
// 检查响应长度
|
if (responseData.length <= 5) {
|
System.out.println("❌ 无效的响应长度: " + responseData.length + " 字节");
|
continue;
|
}
|
//功能码
|
byte responseFunctionCode = responseData[1];
|
//数据字节数
|
byte byteCount = responseData[2];
|
byte[] data = new byte[byteCount];
|
System.arraycopy(responseData, 3, data, 0, byteCount);
|
byte[] crcReceived = new byte[2];
|
System.arraycopy(responseData, responseData.length - 2, crcReceived, 0, 2);
|
// 检查是否为错误响应(功能码 + 0x80)
|
if ((responseFunctionCode & 0x80) != 0) {
|
byte errorCode = responseData[2]; // 错误码
|
System.out.println("❌ 设备返回错误响应,错误码: " + errorCode);
|
continue;
|
}
|
if (DataTypeEnum.OIL.getCode().equals(info.getDataType())) {
|
byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
|
// 解析为浮点数(大端字节顺序)
|
float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN);
|
jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
|
} else if (DataTypeEnum.LIJIUOIL.getCode().equals(info.getDataType())) {
|
byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
|
byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
|
// 解析为浮点数(大端字节顺序)
|
float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
|
jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
|
} else if (DataTypeEnum.LIJIUJUN.getCode().equals(info.getDataType())) {
|
byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
|
// 解析为浮点数(大端字节顺序)
|
float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN);
|
jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
|
} else if (DataTypeEnum.NIGDETUIYOU.getCode().equals(info.getDataType())) {
|
//todo 未做处理
|
byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
|
byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
|
// 解析为浮点数(大端字节顺序)
|
float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
|
jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
|
}
|
}
|
serverSocket.close();
|
return jsonObject;
|
} catch (Exception e) {
|
System.out.println("⚠️ 客户端异常断开: " + e.getMessage());
|
} finally {
|
clientSocket.close();
|
}
|
} catch (Exception e) {
|
if (serverSocket != null) {
|
try {
|
System.out.println("油设备不在线" + e.getMessage());
|
serverSocket.close();
|
} catch (Exception ex) {
|
System.out.println("❌ 油服务端关闭失败: " + ex.getMessage());
|
}
|
} else {
|
System.out.println("❌ 油服务端启动失败: " + e.getMessage());
|
}
|
}
|
return null;
|
}
|
|
/**
|
* @param ip ip
|
* @param port 端口
|
* @param list 查询项列表
|
*/
|
public static JSONObject getLijiuValue(String ip, int port, List<ReceiveOilInfo> list) {
|
// 服务端配置
|
String SERVER_IP = ip; // 监听所有网络接口
|
int SERVER_PORT = port; // 端口号
|
ServerSocket serverSocket = null;
|
try {
|
serverSocket = new ServerSocket(SERVER_PORT);
|
System.out.println("厦门利旧服务端已启动,正在监听 " + SERVER_IP + ":" + SERVER_PORT + "...");
|
serverSocket.setSoTimeout(4000);
|
Socket clientSocket = serverSocket.accept();
|
System.out.println("厦门利旧客户端已连接: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
|
try (InputStream inputStream = clientSocket.getInputStream();
|
OutputStream outputStream = clientSocket.getOutputStream()) {
|
JSONObject jsonObject = new JSONObject();
|
for (ReceiveOilInfo info : list
|
) {
|
// 构造请求帧
|
ByteBuffer requestBuffer = ByteBuffer.allocate(8);
|
if (info.getDeviceAddress() != 0) {
|
requestBuffer.put(info.getDeviceAddress()); // 设备地址
|
}
|
if (info.getFunctionCode() != 0) {
|
requestBuffer.put(info.getFunctionCode()); // 功能码
|
}
|
if (info.getRegisterAdress() != 0) {
|
requestBuffer.putShort((short) info.getRegisterAdress().intValue()); // 寄存器地址
|
}
|
if (info.getRegisterCount() != 0) {
|
requestBuffer.putShort((short) info.getRegisterCount().intValue()); // 寄存器数量
|
}
|
// 计算CRC校验码
|
byte[] requestData = requestBuffer.array();
|
String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
|
int decimal = Integer.parseInt(hex, 16);
|
requestBuffer.putShort((short) decimal); // CRC校验码
|
// 发送请求帧
|
outputStream.write(requestBuffer.array());
|
System.out.println("厦门利旧已发送 MODBUS 请求: " + bytesToHex(requestBuffer.array()));
|
// 接收设备响应
|
byte[] response = new byte[1024];
|
try {
|
Thread.sleep(5000);
|
} catch (Exception ex) {
|
ex.printStackTrace();
|
}
|
int bytesRead = inputStream.read(response);
|
if (bytesRead == -1) {
|
System.out.println("厦门利旧未收到设备响应");
|
continue;
|
}
|
// 打印响应数据
|
byte[] responseData = new byte[bytesRead];
|
System.arraycopy(response, 0, responseData, 0, bytesRead);
|
String resultData = bytesToHex(responseData);
|
System.out.println("厦门利旧收到设备响应: " + resultData);
|
// 检查响应长度
|
if (responseData.length <= 5) {
|
System.out.println("厦门利旧无效的响应长度: " + responseData.length + " 字节");
|
continue;
|
}
|
//功能码
|
byte responseFunctionCode = responseData[1];
|
//数据字节数
|
byte byteCount = responseData[2];
|
byte[] data = new byte[byteCount];
|
System.arraycopy(responseData, 3, data, 0, byteCount);
|
byte[] crcReceived = new byte[2];
|
System.arraycopy(responseData, responseData.length - 2, crcReceived, 0, 2);
|
// 检查是否为错误响应(功能码 + 0x80)
|
if ((responseFunctionCode & 0x80) != 0) {
|
byte errorCode = responseData[2]; // 错误码
|
System.out.println("厦门利旧设备返回错误响应,错误码: " + errorCode);
|
continue;
|
}
|
if (DataTypeEnum.OIL.getCode().equals(info.getDataType())) {
|
byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
|
// 解析为浮点数(大端字节顺序)
|
float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN);
|
jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
|
} else if (DataTypeEnum.LIJIUOIL.getCode().equals(info.getDataType())) {
|
byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
|
byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
|
// 解析为浮点数(大端字节顺序)
|
float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
|
jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
|
} else if (DataTypeEnum.LIJIUJUN.getCode().equals(info.getDataType())) {
|
//todo 未做处理
|
byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
|
byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
|
// 解析为浮点数(大端字节顺序)
|
float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
|
jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
|
} else if (DataTypeEnum.NIGDETUIYOU.getCode().equals(info.getDataType())) {
|
//todo 未做处理
|
byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
|
byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
|
// 解析为浮点数(大端字节顺序)
|
float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
|
jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
|
serverSocket.close();
|
}
|
}
|
return jsonObject;
|
} catch (Exception e) {
|
System.out.println("厦门利旧客户端异常断开: " + e.getMessage());
|
} finally {
|
clientSocket.close();
|
}
|
} catch (Exception e) {
|
if (serverSocket != null) {
|
try {
|
System.out.println("厦门利旧油设备不在线" + e.getMessage());
|
serverSocket.close();
|
} catch (Exception ex) {
|
System.out.println("厦门利旧油服务端关闭失败: " + ex.getMessage());
|
}
|
} else {
|
System.out.println("厦门利旧油服务端启动失败: " + e.getMessage());
|
}
|
}
|
return null;
|
}
|
|
/**
|
* @param ip ip
|
* @param port 端口
|
* @param address 地址码
|
* @param functionCode 功能码
|
* @param registerAddress 寄存器地址
|
* @param registerCount 寄存器数量
|
* @param dataType 结果数据类型
|
*/
|
public static String getValue(String ip, int port, byte address, byte functionCode, int registerAddress, int registerCount, int dataType) {
|
// 服务端配置
|
String SERVER_IP = ip; // 监听所有网络接口
|
int SERVER_PORT = port; // 端口号
|
ServerSocket serverSocket = null;
|
try {
|
serverSocket = new ServerSocket(SERVER_PORT);
|
System.out.println("🛡️ 服务端已启动,正在监听 " + SERVER_IP + ":" + SERVER_PORT + "...");
|
serverSocket.setSoTimeout(8000);
|
Socket clientSocket = serverSocket.accept();
|
System.out.println("🔌 客户端已连接: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
|
try (InputStream inputStream = clientSocket.getInputStream();
|
OutputStream outputStream = clientSocket.getOutputStream()) {
|
// 构造请求帧
|
ByteBuffer requestBuffer = ByteBuffer.allocate(8);
|
if (address != 0) {
|
requestBuffer.put(address); // 设备地址
|
}
|
if (functionCode != 0) {
|
requestBuffer.put(functionCode); // 功能码
|
}
|
if (registerAddress != 0) {
|
requestBuffer.putShort((short) registerAddress); // 寄存器地址
|
}
|
if (registerCount != 0) {
|
requestBuffer.putShort((short) registerCount); // 寄存器数量
|
}
|
// 计算CRC校验码
|
byte[] requestData = requestBuffer.array();
|
String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
|
int decimal = Integer.parseInt(hex, 16);
|
requestBuffer.putShort((short) decimal); // CRC校验码
|
// 发送请求帧
|
outputStream.write(requestBuffer.array());
|
System.out.println("📤 已发送 MODBUS 请求: " + bytesToHex(requestBuffer.array()));
|
// 接收设备响应
|
byte[] response = new byte[1024];
|
try {
|
Thread.sleep(3000);
|
} catch (Exception ex) {
|
ex.printStackTrace();
|
}
|
int bytesRead = inputStream.read(response);
|
if (bytesRead == -1) {
|
System.out.println("❌ 未收到设备响应");
|
return null;
|
}
|
// 打印响应数据
|
byte[] responseData = new byte[bytesRead];
|
System.arraycopy(response, 0, responseData, 0, bytesRead);
|
String resultData = bytesToHex(responseData);
|
System.out.println("📥 收到设备响应: " + resultData);
|
// 检查响应长度
|
if (responseData.length <= 5) {
|
System.out.println("❌ 无效的响应长度: " + responseData.length + " 字节");
|
return null;
|
}
|
//功能码
|
byte responseFunctionCode = responseData[1];
|
//数据字节数
|
byte byteCount = responseData[2];
|
byte[] data = new byte[byteCount];
|
System.arraycopy(responseData, 3, data, 0, byteCount);
|
byte[] crcReceived = new byte[2];
|
System.arraycopy(responseData, responseData.length - 2, crcReceived, 0, 2);
|
// 检查是否为错误响应(功能码 + 0x80)
|
if ((responseFunctionCode & 0x80) != 0) {
|
byte errorCode = responseData[2]; // 错误码
|
System.out.println("❌ 设备返回错误响应,错误码: " + errorCode);
|
return null;
|
}
|
if (DataTypeEnum.OIL.getCode().equals(dataType)) {
|
byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
|
// 解析为浮点数(大端字节顺序)
|
float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN);
|
return String.valueOf(floatValue);
|
} else if (DataTypeEnum.LIJIUOIL.getCode().equals(dataType)) {
|
byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
|
byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
|
// 解析为浮点数(大端字节顺序)
|
float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
|
return String.valueOf(floatValue);
|
} else if (DataTypeEnum.LIJIUJUN.getCode().equals(dataType)) {
|
byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
|
// 解析为浮点数(大端字节顺序)
|
float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN);
|
return String.valueOf(floatValue);
|
} else if (DataTypeEnum.NIGDETUIYOU.getCode().equals(dataType)) {
|
//todo 未做处理
|
byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
|
byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
|
// 解析为浮点数(大端字节顺序)
|
float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
|
return String.valueOf(floatValue);
|
}
|
} catch (IOException e) {
|
System.out.println("⚠️ 客户端异常断开: " + e.getMessage());
|
} finally {
|
clientSocket.close();
|
}
|
} catch (IOException e) {
|
if (serverSocket != null) {
|
try {
|
System.out.println("设备不在线" + e.getMessage());
|
serverSocket.close();
|
} catch (IOException ex) {
|
System.out.println("❌ 服务端关闭失败: " + ex.getMessage());
|
}
|
} else {
|
System.out.println("❌ 服务端启动失败: " + e.getMessage());
|
}
|
}
|
return null;
|
}
|
|
// 将字节数组转换为十六进制字符串
|
public static String bytesToHex(byte[] bytes) {
|
StringBuilder sb = new StringBuilder();
|
for (byte b : bytes) {
|
sb.append(String.format("%02X", b));
|
}
|
return sb.toString();
|
}
|
|
// CRC16 计算
|
public static int crc16(byte[] data) {
|
int crc = 0xFFFF;
|
for (byte b : data) {
|
crc ^= (b & 0xFF);
|
for (int i = 0; i < 8; i++) {
|
if ((crc & 0x0001) != 0) {
|
crc >>= 1;
|
crc ^= 0xA001;
|
} else {
|
crc >>= 1;
|
}
|
}
|
}
|
return crc;
|
}
|
}
|