当前位置: 首页> 财经> 金融 > web前端包括哪些技术_传奇手游sf999发布网_如何做好推广_网站安全检测工具

web前端包括哪些技术_传奇手游sf999发布网_如何做好推广_网站安全检测工具

时间:2025/7/13 10:44:04来源:https://blog.csdn.net/sixpp/article/details/148681645 浏览次数:0次
web前端包括哪些技术_传奇手游sf999发布网_如何做好推广_网站安全检测工具

在这里插入图片描述

文章目录

    • 1. Modbus协议概述
    • 2. Modbus通信方式分类
    • 3. Modbus RTU访问形式及代码示例
      • 3.1 RTU通信特点
      • 3.2 C#实现Modbus RTU通信示例
      • 3.3 Python实现Modbus RTU通信示例
    • 4. Modbus ASCII访问形式及代码示例
      • 4.1 ASCII通信特点
      • 4.2 Java实现Modbus ASCII通信示例
    • 5. Modbus TCP/IP访问形式及代码示例
      • 5.1 TCP/IP通信特点
      • 5.2 C#实现Modbus TCP通信示例
      • 5.3 Python实现Modbus TCP通信示例
    • 6. Modbus over TCP访问形式
      • 6.1 Modbus over TCP特点
      • 6.2 C++实现Modbus over TCP示例

在这里插入图片描述

1. Modbus协议概述

Modbus是一种串行通信协议,最初由Modicon公司(现为施耐德电气)于1979年发布,用于其可编程逻辑控制器(PLC)。Modbus协议已经成为工业领域事实上的标准通信协议,并且现在是工业电子设备之间常用的连接方式。

Modbus协议具有以下特点:

  • 主从式架构(客户端/服务器)
  • 支持多种电气接口(RS-232、RS-485、TCP/IP等)
  • 简单、开放、易于实现
  • 支持多种数据类型的访问

2. Modbus通信方式分类

Modbus通信主要分为以下几种形式:

  1. Modbus RTU(基于串行通信)
  2. Modbus ASCII(基于串行通信)
  3. Modbus TCP/IP(基于以太网)
  4. Modbus over TCP(Modbus TCP的变种)
  5. Modbus Plus(专用网络协议)

3. Modbus RTU访问形式及代码示例

Modbus RTU是最常用的Modbus实现方式,使用二进制编码和紧凑的二进制协议表示数据,采用主从通信方式,通常通过RS-485或RS-232接口实现。

3.1 RTU通信特点

  • 使用二进制数据表示
  • 采用CRC-16校验
  • 通信效率高
  • 典型波特率:9600、19200、38400、115200等

3.2 C#实现Modbus RTU通信示例

using System;
using System.IO.Ports;
using System.Threading;public class ModbusRTU
{private SerialPort _serialPort;private byte _slaveAddress;public ModbusRTU(string portName, int baudRate, byte slaveAddress){_serialPort = new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One);_slavePort.Handshake = Handshake.None;_serialPort.ReadTimeout = 500;_serialPort.WriteTimeout = 500;_slaveAddress = slaveAddress;}public bool Connect(){try{if (!_serialPort.IsOpen){_serialPort.Open();return true;}return false;}catch (Exception ex){Console.WriteLine($"连接失败: {ex.Message}");return false;}}public void Disconnect(){if (_serialPort.IsOpen){_serialPort.Close();}}private byte[] CalculateCRC(byte[] data){ushort crc = 0xFFFF;for (int pos = 0; pos < data.Length; pos++){crc ^= data[pos];for (int i = 8; i != 0; i--){if ((crc & 0x0001) != 0){crc >>= 1;crc ^= 0xA001;}else{crc >>= 1;}}}return new byte[] { (byte)(crc & 0xFF), (byte)((crc >> 8) & 0xFF) };}public bool[] ReadCoils(ushort startAddress, ushort numberOfPoints){byte[] request = new byte[8];request[0] = _slaveAddress;  // 从站地址request[1] = 0x01;           // 功能码request[2] = (byte)(startAddress >> 8);  // 起始地址高字节request[3] = (byte)(startAddress & 0xFF); // 起始地址低字节request[4] = (byte)(numberOfPoints >> 8); // 数量高字节request[5] = (byte)(numberOfPoints & 0xFF); // 数量低字节byte[] crc = CalculateCRC(request, 0, 6);request[6] = crc[0];request[7] = crc[1];_serialPort.Write(request, 0, 8);Thread.Sleep(50); // 等待响应int bytesToRead = _serialPort.BytesToRead;byte[] response = new byte[bytesToRead];_serialPort.Read(response, 0, bytesToRead);// 验证响应if (response.Length < 5 || response[0] != _slaveAddress || response[1] != 0x01){throw new Exception("无效的响应");}byte[] receivedCrc = new byte[] { response[response.Length - 2], response[response.Length - 1] };byte[] calculatedCrc = CalculateCRC(response, 0, response.Length - 2);if (receivedCrc[0] != calculatedCrc[0] || receivedCrc[1] != calculatedCrc[1]){throw new Exception("CRC校验失败");}int byteCount = response[2];bool[] coils = new bool[numberOfPoints];for (int i = 0; i < numberOfPoints; i++){int byteIndex = 3 + (i / 8);int bitIndex = i % 8;coils[i] = (response[byteIndex] & (1 << bitIndex)) != 0;}return coils;}// 其他功能码实现类似...
}

3.3 Python实现Modbus RTU通信示例

import serial
import time
from crcmod import mkCrcFunclass ModbusRTU:def __init__(self, port, baudrate=9600, slave_address=1, timeout=1):self.serial = serial.Serial(port=port,baudrate=baudrate,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_ONE,bytesize=serial.EIGHTBITS,timeout=timeout)self.slave_address = slave_addressself.crc16 = mkCrcFun(0x18005, rev=True, initCrc=0xFFFF, xorOut=0x0000)def _calculate_crc(self, data):return self.crc16(data).to_bytes(2, 'little')def _send_receive(self, pdu):# 构建ADU: 从站地址 + PDU + CRCadu = bytes([self.slave_address]) + pducrc = self._calculate_crc(adu)adu += crc# 发送请求self.serial.write(adu)# 等待响应time.sleep(0.1)  # 根据波特率调整# 读取响应response = self.serial.read(256)if len(response) < 5:raise Exception("响应数据过短")# 验证CRCreceived_crc = response[-2:]calculated_crc = self._calculate_crc(response[:-2])if received_crc != calculated_crc:raise Exception("CRC校验失败")# 验证从站地址if response[0] != self.slave_address:raise Exception("从站地址不匹配")return response[1:-2]  # 返回PDU部分def read_holding_registers(self, start_address, quantity):if quantity < 1 or quantity > 125:raise ValueError("数量必须在1-125之间")pdu = bytes([0x03,  # 功能码(start_address >> 8) & 0xFF,  # 起始地址高字节start_address & 0xFF,         # 起始地址低字节(quantity >> 8) & 0xFF,       # 数量高字节quantity & 0xFF               # 数量低字节])response_pdu = self._send_receive(pdu)if response_pdu[0] != 0x03:raise Exception("无效的功能码响应")byte_count = response_pdu[1]if byte_count != quantity * 2:raise Exception("返回数据长度不匹配")registers = []for i in range(quantity):idx = 2 + i * 2value = (response_pdu[idx] << 8) + response_pdu[idx + 1]registers.append(value)return registersdef write_single_register(self, address, value):pdu = bytes([0x06,  # 功能码(address >> 8) & 0xFF,  # 地址高字节address & 0xFF,          # 地址低字节(value >> 8) & 0xFF,     # 值高字节value & 0xFF             # 值低字节])response_pdu = self._send_receive(pdu)if len(response_pdu) != 5 or response_pdu != pdu:raise Exception("写入失败")return Truedef close(self):if self.serial.is_open:self.serial.close()

4. Modbus ASCII访问形式及代码示例

Modbus ASCII是Modbus协议的另一种串行传输模式,使用ASCII字符表示十六进制数据,每个字节用两个ASCII字符表示。

4.1 ASCII通信特点

  • 使用ASCII字符表示数据
  • 采用LRC校验
  • 可读性较好
  • 通信效率低于RTU模式
  • 以冒号(:)开始,以CRLF结束

4.2 Java实现Modbus ASCII通信示例

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.TooManyListenersException;
import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;public class ModbusASCII {private SerialPort serialPort;private OutputStream out;private BufferedReader in;private int slaveAddress;private static final int TIMEOUT = 2000;public ModbusASCII(String portName, int baudRate, int slaveAddress) throws Exception {this.slaveAddress = slaveAddress;CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);if (portIdentifier.isCurrentlyOwned()) {throw new Exception("端口已被占用");}CommPort commPort = portIdentifier.open(this.getClass().getName(), TIMEOUT);if (commPort instanceof SerialPort) {serialPort = (SerialPort) commPort;serialPort.setSerialPortParams(baudRate, SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);serialPort.enableReceiveTimeout(TIMEOUT);out = serialPort.getOutputStream();in = new BufferedReader(new InputStreamReader(serialPort.getInputStream()));} else {throw new Exception("不是串口");}}public void close() {if (serialPort != null) {serialPort.close();}}private byte calculateLRC(byte[] data) {byte lrc = 0;for (byte b : data) {lrc += b;}return (byte) (-lrc);}private String bytesToASCII(byte[] data) {StringBuilder sb = new StringBuilder();sb.append(":");for (byte b : data) {sb.append(String.format("%02X", b));}byte lrc = calculateLRC(data);sb.append(String.format("%02X", lrc));sb.append("\r\n");return sb.toString();}private byte[] ASCIIToBytes(String ascii) {if (!ascii.startsWith(":") || !ascii.endsWith("\r\n")) {throw new IllegalArgumentException("无效的ASCII格式");}String content = ascii.substring(1, ascii.length() - 2);if (content.length() % 2 != 0) {throw new IllegalArgumentException("无效的ASCII长度");}byte[] bytes = new byte[content.length() / 2];for (int i = 0; i < bytes.length; i++) {String hex = content.substring(i * 2, i * 2 + 2);bytes[i] = (byte) Integer.parseInt(hex, 16);}// 验证LRCbyte calculatedLRC = calculateLRC(Arrays.copyOfRange(bytes, 0, bytes.length - 1));byte receivedLRC = bytes[bytes.length - 1];if (calculatedLRC != receivedLRC) {throw new IllegalArgumentException("LRC校验失败");}return Arrays.copyOfRange(bytes, 0, bytes.length - 1);}public int[] readHoldingRegisters(int startAddress, int quantity) throws Exception {if (quantity < 1 || quantity > 125) {throw new IllegalArgumentException("数量必须在1-125之间");}byte[] pdu = new byte[5];pdu[0] = (byte) slaveAddress;  // 从站地址pdu[1] = 0x03;                // 功能码pdu[2] = (byte) (startAddress >> 8);  // 起始地址高字节pdu[3] = (byte) (startAddress & 0xFF); // 起始地址低字节pdu[4] = (byte) quantity;      // 寄存器数量String request = bytesToASCII(pdu);out.write(request.getBytes());out.flush();String response = in.readLine();byte[] responseBytes = ASCIIToBytes(response);if (responseBytes.length < 3 || responseBytes[0] != pdu[0] || responseBytes[1] != pdu[1]) {throw new Exception("无效的响应");}int byteCount = responseBytes[2] & 0xFF;if (byteCount != quantity * 2) {throw new Exception("返回数据长度不匹配");}int[] registers = new int[quantity];for (int i = 0; i < quantity; i++) {int idx = 3 + i * 2;registers[i] = ((responseBytes[idx] & 0xFF) << 8) | (responseBytes[idx + 1] & 0xFF);}return registers;}public boolean writeSingleRegister(int address, int value) throws Exception {byte[] pdu = new byte[5];pdu[0] = (byte) slaveAddress;  // 从站地址pdu[1] = 0x06;                // 功能码pdu[2] = (byte) (address >> 8);  // 地址高字节pdu[3] = (byte) (address & 0xFF); // 地址低字节pdu[4] = (byte) (value >> 8);    // 值高字节pdu[5] = (byte) (value & 0xFF);   // 值低字节String request = bytesToASCII(pdu);out.write(request.getBytes());out.flush();String response = in.readLine();byte[] responseBytes = ASCIIToBytes(response);if (responseBytes.length != pdu.length || !Arrays.equals(responseBytes, pdu)) {throw new Exception("写入失败");}return true;}
}

5. Modbus TCP/IP访问形式及代码示例

Modbus TCP/IP是Modbus协议在TCP/IP网络上的实现,它去掉了RTU和ASCII模式中的校验码,使用TCP的错误检测机制。

5.1 TCP/IP通信特点

  • 基于标准TCP/IP协议
  • 使用端口502(默认)
  • 不需要校验码
  • 增加了MBAP头(Modbus Application Protocol header)
  • 支持多设备同时访问

5.2 C#实现Modbus TCP通信示例

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;public class ModbusTCP
{private string _ipAddress;private int _port;private ushort _transactionId = 0;public ModbusTCP(string ipAddress, int port = 502){_ipAddress = ipAddress;_port = port;}private byte[] BuildReadHoldingRegistersRequest(byte unitId, ushort startAddress, ushort numberOfRegisters){_transactionId++;byte[] packet = new byte[12];// MBAP头packet[0] = (byte)(_transactionId >> 8);  // 事务ID高字节packet[1] = (byte)(_transactionId & 0xFF); // 事务ID低字节packet[2] = 0x00;  // 协议ID高字节 (Modbus=0)packet[3] = 0x00;  // 协议ID低字节 (Modbus=0)packet[4] = 0x00;  // 长度高字节 (后面设置)packet[5] = 0x06;  // 长度低字节 (剩余6字节)// PDUpacket[6] = unitId;  // 单元IDpacket[7] = 0x03;   // 功能码packet[8] = (byte)(startAddress >> 8);  // 起始地址高字节packet[9] = (byte)(startAddress & 0xFF); // 起始地址低字节packet[10] = (byte)(numberOfRegisters >> 8); // 寄存器数量高字节packet[11] = (byte)(numberOfRegisters & 0xFF); // 寄存器数量低字节return packet;}private ushort[] ParseReadHoldingRegistersResponse(byte[] response){if (response.Length < 9){throw new Exception("响应数据过短");}// 检查事务IDushort transId = (ushort)((response[0] << 8) + response[1]);if (transId != _transactionId){throw new Exception("事务ID不匹配");}// 检查协议IDushort protocolId = (ushort)((response[2] << 8) + response[3]);if (protocolId != 0){throw new Exception("协议ID不正确");}// 检查单元IDbyte unitId = response[6];// 检查功能码byte functionCode = response[7];if (functionCode != 0x03){if (functionCode == 0x83)  // 错误响应{byte errorCode = response[8];throw new Exception($"Modbus错误: {GetModbusErrorDescription(errorCode)}");}throw new Exception("功能码不正确");}// 获取数据byte byteCount = response[8];if (byteCount % 2 != 0 || byteCount > response.Length - 9){throw new Exception("数据长度不正确");}ushort[] registers = new ushort[byteCount / 2];for (int i = 0; i < registers.Length; i++){int offset = 9 + i * 2;registers[i] = (ushort)((response[offset] << 8) + response[offset + 1]);}return registers;}public ushort[] ReadHoldingRegisters(byte unitId, ushort startAddress, ushort numberOfRegisters){try{using (TcpClient client = new TcpClient(_ipAddress, _port)){client.SendTimeout = 1000;client.ReceiveTimeout = 1000;NetworkStream stream = client.GetStream();byte[] request = BuildReadHoldingRegistersRequest(unitId, startAddress, numberOfRegisters);stream.Write(request, 0, request.Length);byte[] buffer = new byte[256];int bytesRead = stream.Read(buffer, 0, buffer.Length);if (bytesRead == 0){throw new Exception("未收到响应");}byte[] response = new byte[bytesRead];Array.Copy(buffer, response, bytesRead);return ParseReadHoldingRegistersResponse(response);}}catch (Exception ex){throw new Exception($"通信失败: {ex.Message}", ex);}}private string GetModbusErrorDescription(byte errorCode){switch (errorCode){case 0x01: return "非法功能";case 0x02: return "非法数据地址";case 0x03: return "非法数据值";case 0x04: return "从站设备故障";case 0x05: return "确认";case 0x06: return "从站设备忙";case 0x07: return "否定应答";case 0x08: return "内存奇偶错误";case 0x0A: return "网关路径不可用";case 0x0B: return "网关目标设备响应失败";default: return $"未知错误 ({errorCode:X2})";}}// 其他功能码实现...
}

5.3 Python实现Modbus TCP通信示例

import socket
import struct
from typing import Listclass ModbusTCP:def __init__(self, host: str, port: int = 502, timeout: float = 5.0):self.host = hostself.port = portself.timeout = timeoutself.transaction_id = 0self.socket = Nonedef connect(self):"""建立TCP连接"""if self.socket is None:self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)self.socket.settimeout(self.timeout)self.socket.connect((self.host, self.port))def close(self):"""关闭TCP连接"""if self.socket is not None:self.socket.close()self.socket = Nonedef _build_mbap_header(self, unit_id: int, pdu_length: int) -> bytes:"""构建MBAP头"""self.transaction_id = (self.transaction_id + 1) % 65536return struct.pack(">HHHBB",self.transaction_id,  # 事务ID0x0000,             # 协议ID (Modbus=0)pdu_length + 1,     # 长度 (PDU长度 + 单元ID)unit_id,            # 单元ID)def _send_receive(self, unit_id: int, pdu: bytes) -> bytes:"""发送请求并接收响应"""if self.socket is None:self.connect()# 构建完整的请求帧request = self._build_mbap_header(unit_id, len(pdu)) + pdu# 发送请求self.socket.sendall(request)# 接收MBAP头 (7字节)mbap_header = self._receive_exact(7)if len(mbap_header) != 7:raise Exception("接收MBAP头失败")# 解析MBAP头trans_id, proto_id, length, unit_id_resp = struct.unpack(">HHHB", mbap_header)# 验证事务IDif trans_id != self.transaction_id:raise Exception("事务ID不匹配")# 验证协议IDif proto_id != 0:raise Exception("协议ID不正确")# 接收剩余数据 (length-1字节)pdu_length = length - 1pdu_data = self._receive_exact(pdu_length)return pdu_datadef _receive_exact(self, length: int) -> bytes:"""接收指定长度的数据"""data = bytearray()while len(data) < length:chunk = self.socket.recv(length - len(data))if not chunk:breakdata.extend(chunk)return bytes(data)def read_holding_registers(self, unit_id: int, start_address: int, quantity: int) -> List[int]:"""读取保持寄存器 (功能码0x03)"""if quantity < 1 or quantity > 125:raise ValueError("数量必须在1-125之间")# 构建PDUpdu = struct.pack(">BHH", 0x03, start_address, quantity)# 发送并接收响应response_pdu = self._send_receive(unit_id, pdu)# 解析响应if len(response_pdu) < 2 or response_pdu[0] != 0x03:if len(response_pdu) >= 2 and response_pdu[0] == 0x83:error_code = response_pdu[1]raise Exception(f"Modbus错误: {self._get_error_description(error_code)}")raise Exception("无效的响应")byte_count = response_pdu[1]if byte_count != quantity * 2:raise Exception("返回数据长度不匹配")registers = []for i in range(quantity):idx = 2 + i * 2value = struct.unpack_from(">H", response_pdu, idx)[0]registers.append(value)return registersdef write_single_register(self, unit_id: int, address: int, value: int) -> bool:"""写入单个寄存器 (功能码0x06)"""# 构建PDUpdu = struct.pack(">BHH", 0x06, address, value)# 发送并接收响应response_pdu = self._send_receive(unit_id, pdu)# 验证响应if len(response_pdu) != 5 or response_pdu != pdu:raise Exception("写入失败")return Truedef write_multiple_registers(self, unit_id: int, start_address: int, values: List[int]) -> bool:"""写入多个寄存器 (功能码0x10)"""quantity = len(values)if quantity < 1 or quantity > 123:raise ValueError("数量必须在1-123之间")# 构建PDUbyte_count = quantity * 2pdu = bytearray()pdu.extend(struct.pack(">BHHB", 0x10, start_address, quantity, byte_count))# 添加寄存器值for value in values:pdu.extend(struct.pack(">H", value))# 发送并接收响应response_pdu = self._send_receive(unit_id, pdu)# 验证响应if len(response_pdu) != 5 or response_pdu[0] != 0x10:if len(response_pdu) >= 2 and response_pdu[0] == 0x90:error_code = response_pdu[1]raise Exception(f"Modbus错误: {self._get_error_description(error_code)}")raise Exception("写入失败")# 验证地址和数量resp_address, resp_quantity = struct.unpack_from(">HH", response_pdu, 1)if resp_address != start_address or resp_quantity != quantity:raise Exception("写入验证失败")return Truedef _get_error_description(self, error_code: int) -> str:"""获取Modbus错误描述"""errors = {0x01: "非法功能",0x02: "非法数据地址",0x03: "非法数据值",0x04: "从站设备故障",0x05: "确认",0x06: "从站设备忙",0x07: "否定应答",0x08: "内存奇偶错误",0x0A: "网关路径不可用",0x0B: "网关目标设备响应失败",}return errors.get(error_code, f"未知错误 ({error_code:X2})")

6. Modbus over TCP访问形式

Modbus over TCP是Modbus TCP的一种变体,主要用于通过TCP隧道传输Modbus RTU或ASCII帧。

6.1 Modbus over TCP特点

  • 保留RTU或ASCII帧格式
  • 通过TCP传输
  • 不需要MBAP头
  • 常用于串口转以太网设备

6.2 C++实现Modbus over TCP示例

#include <iostream>
#include <vector>
#include <string>
#include <winsock2.h>
#include <ws2tcpip.h>#pragma comment(lib, "ws2_32.lib")class ModbusOverTCP {
private:SOCKET sock;std::string host;int port;bool connected;public:ModbusOverTCP(const std::string& host, int port = 502) : host(host), port(port), connected(false), sock(INVALID_SOCKET) {WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {throw std::runtime_error("WSAStartup failed");}}~ModbusOverTCP() {disconnect();WSACleanup();}bool connect() {if (connected) return true;sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (sock == INVALID_SOCKET) {return false;}sockaddr_in serverAddr;serverAddr.sin_family = AF_INET;serverAddr.sin_port = htons(port);inet_pton(AF_INET, host.c_str(), &serverAddr.sin_addr);if (::connect(sock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {closesocket(sock);sock = INVALID_SOCKET;return false;}connected = true;return true;}void disconnect() {if (connected) {closesocket(sock);sock = INVALID_SOCKET;connected = false;}}std::vector<uint8_t> readHoldingRegisters(uint8_t slaveId, uint16_t startAddr, uint16_t quantity) {if (!connected && !connect()) {throw std::runtime_error("连接失败");}// 构建RTU请求帧 (无CRC)std::vector<uint8_t> request = {slaveId,    // 从站地址0x03,       // 功能码static_cast<uint8_t>(startAddr >> 8),    // 起始地址高字节static_cast<uint8_t>(startAddr & 0xFF),  // 起始地址低字节static_cast<uint8_t>(quantity >> 8),     // 数量高字节static_cast<uint8_t>(quantity & 0xFF)    // 数量低字节};// 发送请求if (send(sock, reinterpret_cast<char*>(request.data()), request.size(), 0) == SOCKET_ERROR) {throw std::runtime_error("发送失败");}// 接收响应头 (至少5字节)std::vector<uint8_t> response(256);int bytesRead = recv(sock, reinterpret_cast<char*>(response.data()), response.size(), 0);if (bytesRead == SOCKET_ERROR || bytesRead < 5) {throw std::runtime_error("接收失败");}response.resize(bytesRead);// 验证响应if (response[0] != slaveId || response[1] != 0x03) {if (response.size() >= 2 && response[1] == 0x83) {throw std::runtime_error("Modbus错误: " + getErrorDescription(response[2]));}throw std::runtime_error("无效的响应");}uint8_t byteCount = response[2];if (byteCount != quantity * 2) {throw std::runtime_error("数据长度不匹配");}return std::vector<uint8_t>(response.begin() + 3, response.begin() + 3 + byteCount);}bool writeSingleRegister(uint8_t slaveId, uint16_t addr, uint16_t value) {if (!connected && !connect()) {throw std::runtime_error("连接失败");}// 构建RTU请求帧 (无CRC)std::vector<uint8_t> request = {slaveId,    // 从站地址0x06,       // 功能码static_cast<uint8_t>(addr >> 8),     // 地址高字节static_cast<uint8_t>(addr & 0xFF),   // 地址低字节static_cast<uint8_t>(value >> 8),    // 值高字节static_cast<uint8_t>(value & 0xFF)   // 值低字节};// 发送请求if (send(sock, reinterpret_cast<char*>(request.data()), request.size(), 0) == SOCKET_ERROR) {throw std::runtime_error("发送失败");}// 接收响应std::vector<uint8_t> response(8);int bytesRead = recv(sock, reinterpret_cast<char*>(response.data()), response.size(), 0);if (bytesRead == SOCKET_ERROR || bytesRead < request.size()) {throw std::runtime_error("接收失败");}response.resize(bytesRead);// 验证响应if (response != request) {if (response.size() >= 2 && response[1] == 0x86) {throw std::runtime_error("Modbus错误: " + getErrorDescription(response[2]));}throw std::runtime_error("写入失败");}return true;}private:std::string getErrorDescription(uint8_t errorCode) {switch (errorCode) {case 0x01: return "非法功能";case 0x02: return "非法数据地址";case 0x03: return "非法数据值";case 0x04: return "从站设备故障";case 0x05: return "确认";case 0x06: return "从站设备忙";case 0x07: return "否定应答";case 0x08: return "内存奇偶错误";case 0x0A: return "网关路径不可用";case 0x0B: return "网关目标设备响应失败";default: return "未知错误";}}
};

在实际项目中,应根据具体需求选择合适的Modbus实现方式,并考虑性能、可靠性和安全性等因素。本文提供的代码示例可以作为开发起点,但实际应用中还需要根据具体场景进行调整和优化。

随着工业物联网(IIoT)的发展,Modbus协议仍然在工业自动化领域扮演着重要角色,理解并掌握其各种访问形式对于工业软件开发人员来说是一项基本而重要的技能。

关键字:web前端包括哪些技术_传奇手游sf999发布网_如何做好推广_网站安全检测工具

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: