工业自动化通信控制

工业自动化通信控制

目录

  1. 串口通信控制
  2. 网口通信控制
  3. 物联网控制
  4. 综合应用案例
  5. 最佳实践与故障排查

串口通信控制

1.1 串口通信基础

串口通信是工业自动化中最常用的通信方式之一,主要包括RS232、RS485和RS422标准。

核心概念
  • 波特率(Baud Rate): 数据传输速率,常用值:9600、19200、38400、115200
  • 数据位(Data Bits): 通常为7位或8位
  • 停止位(Stop Bits): 1位、1.5位或2位
  • 校验位(Parity): 无校验(None)、奇校验(Odd)、偶校验(Even)
  • 流控制(Flow Control): 硬件流控(RTS/CTS)或软件流控(XON/XOFF)
RS232 vs RS485
特性 RS232 RS485
传输距离 ≤15米 ≤1200米
传输方式 全双工 半双工/全双工
设备数量 1对1 最多128个设备
抗干扰性 较弱 强(差分信号)
应用场景 近距离点对点 工业现场总线

1.2 C# 串口通信实现

基础串口类封装
csharp 复制代码
using System;
using System.IO.Ports;
using System.Text;
using System.Threading;

namespace IndustrialAutomation
{
    public class SerialPortManager : IDisposable
    {
        private SerialPort _serialPort;
        private bool _isConnected = false;
        
        // 数据接收事件
        public event EventHandler<string> DataReceived;
        public event EventHandler<Exception> ErrorOccurred;
        
        /// <summary>
        /// 初始化串口
        /// </summary>
        public SerialPortManager(string portName, int baudRate = 9600, 
                                Parity parity = Parity.None, 
                                int dataBits = 8, 
                                StopBits stopBits = StopBits.One)
        {
            _serialPort = new SerialPort
            {
                PortName = portName,
                BaudRate = baudRate,
                Parity = parity,
                DataBits = dataBits,
                StopBits = stopBits,
                Handshake = Handshake.None,
                ReadTimeout = 1000,
                WriteTimeout = 1000
            };
            
            _serialPort.DataReceived += SerialPort_DataReceived;
            _serialPort.ErrorReceived += SerialPort_ErrorReceived;
        }
        
        /// <summary>
        /// 打开串口
        /// </summary>
        public bool Open()
        {
            try
            {
                if (!_serialPort.IsOpen)
                {
                    _serialPort.Open();
                    _isConnected = true;
                    Console.WriteLine($"串口 {_serialPort.PortName} 已打开");
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                ErrorOccurred?.Invoke(this, ex);
                return false;
            }
        }
        
        /// <summary>
        /// 关闭串口
        /// </summary>
        public void Close()
        {
            if (_serialPort != null && _serialPort.IsOpen)
            {
                _serialPort.Close();
                _isConnected = false;
                Console.WriteLine("串口已关闭");
            }
        }
        
        /// <summary>
        /// 发送字符串数据
        /// </summary>
        public bool SendString(string data)
        {
            try
            {
                if (_serialPort.IsOpen)
                {
                    _serialPort.WriteLine(data);
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                ErrorOccurred?.Invoke(this, ex);
                return false;
            }
        }
        
        /// <summary>
        /// 发送字节数组(常用于Modbus等协议)
        /// </summary>
        public bool SendBytes(byte[] data)
        {
            try
            {
                if (_serialPort.IsOpen)
                {
                    _serialPort.Write(data, 0, data.Length);
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                ErrorOccurred?.Invoke(this, ex);
                return false;
            }
        }
        
        /// <summary>
        /// 发送并等待响应
        /// </summary>
        public byte[] SendAndReceive(byte[] sendData, int expectedLength, int timeout = 1000)
        {
            try
            {
                if (!_serialPort.IsOpen) return null;
                
                _serialPort.DiscardInBuffer();
                _serialPort.Write(sendData, 0, sendData.Length);
                
                Thread.Sleep(50); // 等待设备响应
                
                byte[] buffer = new byte[expectedLength];
                int bytesRead = _serialPort.Read(buffer, 0, expectedLength);
                
                if (bytesRead == expectedLength)
                    return buffer;
                
                return null;
            }
            catch (Exception ex)
            {
                ErrorOccurred?.Invoke(this, ex);
                return null;
            }
        }
        
        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                string data = _serialPort.ReadExisting();
                DataReceived?.Invoke(this, data);
            }
            catch (Exception ex)
            {
                ErrorOccurred?.Invoke(this, ex);
            }
        }
        
        private void SerialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
        {
            ErrorOccurred?.Invoke(this, new Exception($"串口错误: {e.EventType}"));
        }
        
        public void Dispose()
        {
            Close();
            _serialPort?.Dispose();
        }
    }
}
Modbus RTU 协议实现
csharp 复制代码
public class ModbusRTU
{
    private SerialPortManager _serialPort;
    
    public ModbusRTU(string portName, int baudRate = 9600)
    {
        _serialPort = new SerialPortManager(portName, baudRate);
    }
    
    /// <summary>
    /// 读取保持寄存器 (功能码 0x03)
    /// </summary>
    public ushort[] ReadHoldingRegisters(byte slaveId, ushort startAddress, ushort quantity)
    {
        // 构建请求报文
        byte[] request = new byte[8];
        request[0] = slaveId;           // 从站地址
        request[1] = 0x03;              // 功能码
        request[2] = (byte)(startAddress >> 8);   // 起始地址高字节
        request[3] = (byte)(startAddress & 0xFF); // 起始地址低字节
        request[4] = (byte)(quantity >> 8);       // 寄存器数量高字节
        request[5] = (byte)(quantity & 0xFF);     // 寄存器数量低字节
        
        // 计算CRC校验
        ushort crc = CalculateCRC(request, 6);
        request[6] = (byte)(crc & 0xFF);
        request[7] = (byte)(crc >> 8);
        
        // 发送并接收响应
        int expectedLength = 5 + (quantity * 2);
        byte[] response = _serialPort.SendAndReceive(request, expectedLength, 1000);
        
        if (response == null || !ValidateCRC(response))
            throw new Exception("Modbus通信错误或CRC校验失败");
        
        // 解析数据
        ushort[] values = new ushort[quantity];
        for (int i = 0; i < quantity; i++)
        {
            values[i] = (ushort)((response[3 + i * 2] << 8) | response[4 + i * 2]);
        }
        
        return values;
    }
    
    /// <summary>
    /// 写单个寄存器 (功能码 0x06)
    /// </summary>
    public bool WriteSingleRegister(byte slaveId, ushort address, ushort value)
    {
        byte[] request = new byte[8];
        request[0] = slaveId;
        request[1] = 0x06;
        request[2] = (byte)(address >> 8);
        request[3] = (byte)(address & 0xFF);
        request[4] = (byte)(value >> 8);
        request[5] = (byte)(value & 0xFF);
        
        ushort crc = CalculateCRC(request, 6);
        request[6] = (byte)(crc & 0xFF);
        request[7] = (byte)(crc >> 8);
        
        byte[] response = _serialPort.SendAndReceive(request, 8, 1000);
        return response != null && ValidateCRC(response);
    }
    
    /// <summary>
    /// CRC16校验计算
    /// </summary>
    private ushort CalculateCRC(byte[] data, int length)
    {
        ushort crc = 0xFFFF;
        for (int i = 0; i < length; i++)
        {
            crc ^= data[i];
            for (int j = 0; j < 8; j++)
            {
                if ((crc & 0x0001) != 0)
                    crc = (ushort)((crc >> 1) ^ 0xA001);
                else
                    crc >>= 1;
            }
        }
        return crc;
    }
    
    private bool ValidateCRC(byte[] data)
    {
        if (data.Length < 2) return false;
        ushort receivedCRC = (ushort)(data[data.Length - 2] | (data[data.Length - 1] << 8));
        ushort calculatedCRC = CalculateCRC(data, data.Length - 2);
        return receivedCRC == calculatedCRC;
    }
}

1.3 Python 串口通信实现

基础串口操作
python 复制代码
import serial
import serial.tools.list_ports
import time
import struct
from typing import Optional, List

class SerialPortManager:
    """串口管理器类"""
    
    def __init__(self, port: str, baudrate: int = 9600, 
                 timeout: float = 1.0, **kwargs):
        """
        初始化串口
        
        Args:
            port: 串口名称 (如 'COM1' 或 '/dev/ttyUSB0')
            baudrate: 波特率
            timeout: 超时时间(秒)
            **kwargs: 其他serial.Serial参数
        """
        self.port = port
        self.baudrate = baudrate
        self.timeout = timeout
        self.serial = None
        self.kwargs = kwargs
        
    def open(self) -> bool:
        """打开串口"""
        try:
            self.serial = serial.Serial(
                port=self.port,
                baudrate=self.baudrate,
                timeout=self.timeout,
                bytesize=serial.EIGHTBITS,
                parity=serial.PARITY_NONE,
                stopbits=serial.STOPBITS_ONE,
                **self.kwargs
            )
            print(f"串口 {self.port} 已打开")
            return True
        except serial.SerialException as e:
            print(f"打开串口失败: {e}")
            return False
    
    def close(self):
        """关闭串口"""
        if self.serial and self.serial.is_open:
            self.serial.close()
            print("串口已关闭")
    
    def send_string(self, data: str, encoding: str = 'utf-8') -> bool:
        """发送字符串"""
        try:
            if self.serial and self.serial.is_open:
                self.serial.write(data.encode(encoding))
                return True
            return False
        except Exception as e:
            print(f"发送数据失败: {e}")
            return False
    
    def send_bytes(self, data: bytes) -> bool:
        """发送字节数据"""
        try:
            if self.serial and self.serial.is_open:
                self.serial.write(data)
                return True
            return False
        except Exception as e:
            print(f"发送数据失败: {e}")
            return False
    
    def read_bytes(self, size: int = 1) -> Optional[bytes]:
        """读取指定字节数"""
        try:
            if self.serial and self.serial.is_open:
                return self.serial.read(size)
            return None
        except Exception as e:
            print(f"读取数据失败: {e}")
            return None
    
    def read_until(self, terminator: bytes = b'\n') -> Optional[bytes]:
        """读取直到遇到终止符"""
        try:
            if self.serial and self.serial.is_open:
                return self.serial.read_until(terminator)
            return None
        except Exception as e:
            print(f"读取数据失败: {e}")
            return None
    
    def send_and_receive(self, send_data: bytes, 
                        expected_length: int, 
                        delay: float = 0.05) -> Optional[bytes]:
        """发送数据并等待响应"""
        try:
            if not self.serial or not self.serial.is_open:
                return None
            
            self.serial.reset_input_buffer()
            self.serial.write(send_data)
            time.sleep(delay)
            
            response = self.serial.read(expected_length)
            return response if len(response) == expected_length else None
        except Exception as e:
            print(f"通信失败: {e}")
            return None
    
    @staticmethod
    def list_ports() -> List[str]:
        """列出所有可用串口"""
        ports = serial.tools.list_ports.comports()
        return [port.device for port in ports]
    
    def __enter__(self):
        self.open()
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()


class ModbusRTU:
    """Modbus RTU协议实现"""
    
    def __init__(self, port: str, baudrate: int = 9600):
        self.serial_manager = SerialPortManager(port, baudrate)
    
    def open(self):
        return self.serial_manager.open()
    
    def close(self):
        self.serial_manager.close()
    
    def read_holding_registers(self, slave_id: int, 
                              start_address: int, 
                              quantity: int) -> Optional[List[int]]:
        """
        读取保持寄存器 (功能码 0x03)
        
        Args:
            slave_id: 从站地址
            start_address: 起始地址
            quantity: 寄存器数量
            
        Returns:
            寄存器值列表
        """
        # 构建请求报文
        request = struct.pack('>BBHH',
            slave_id,        # 从站地址
            0x03,            # 功能码
            start_address,   # 起始地址
            quantity         # 寄存器数量
        )
        
        # 添加CRC校验
        crc = self._calculate_crc(request)
        request += struct.pack('<H', crc)
        
        # 发送并接收
        expected_length = 5 + (quantity * 2)
        response = self.serial_manager.send_and_receive(request, expected_length)
        
        if not response or not self._validate_crc(response):
            print("Modbus通信错误或CRC校验失败")
            return None
        
        # 解析数据
        values = []
        for i in range(quantity):
            offset = 3 + (i * 2)
            value = struct.unpack('>H', response[offset:offset+2])[0]
            values.append(value)
        
        return values
    
    def write_single_register(self, slave_id: int, 
                            address: int, 
                            value: int) -> bool:
        """
        写单个寄存器 (功能码 0x06)
        """
        request = struct.pack('>BBHH',
            slave_id,
            0x06,
            address,
            value
        )
        
        crc = self._calculate_crc(request)
        request += struct.pack('<H', crc)
        
        response = self.serial_manager.send_and_receive(request, 8)
        return response is not None and self._validate_crc(response)
    
    def write_multiple_registers(self, slave_id: int,
                                start_address: int,
                                values: List[int]) -> bool:
        """
        写多个寄存器 (功能码 0x10)
        """
        quantity = len(values)
        byte_count = quantity * 2
        
        # 构建请求头
        request = struct.pack('>BBHHB',
            slave_id,
            0x10,
            start_address,
            quantity,
            byte_count
        )
        
        # 添加数据
        for value in values:
            request += struct.pack('>H', value)
        
        # 添加CRC
        crc = self._calculate_crc(request)
        request += struct.pack('<H', crc)
        
        response = self.serial_manager.send_and_receive(request, 8)
        return response is not None and self._validate_crc(response)
    
    @staticmethod
    def _calculate_crc(data: bytes) -> int:
        """计算CRC16校验"""
        crc = 0xFFFF
        for byte in data:
            crc ^= byte
            for _ in range(8):
                if crc & 0x0001:
                    crc = (crc >> 1) ^ 0xA001
                else:
                    crc >>= 1
        return crc
    
    @staticmethod
    def _validate_crc(data: bytes) -> bool:
        """验证CRC校验"""
        if len(data) < 2:
            return False
        received_crc = struct.unpack('<H', data[-2:])[0]
        calculated_crc = ModbusRTU._calculate_crc(data[:-2])
        return received_crc == calculated_crc
使用示例
python 复制代码
# 示例1: 基础串口通信
with SerialPortManager('/dev/ttyUSB0', 9600) as serial_mgr:
    # 发送字符串
    serial_mgr.send_string("Hello Device\n")
    
    # 读取响应
    response = serial_mgr.read_until(b'\n')
    print(f"收到: {response.decode()}")

# 示例2: Modbus RTU通信
modbus = ModbusRTU('/dev/ttyUSB0', 9600)
modbus.open()

try:
    # 读取从站1的保持寄存器
    values = modbus.read_holding_registers(slave_id=1, start_address=0, quantity=10)
    if values:
        print(f"读取到的寄存器值: {values}")
    
    # 写入单个寄存器
    success = modbus.write_single_register(slave_id=1, address=0, value=1234)
    print(f"写入{'成功' if success else '失败'}")
    
finally:
    modbus.close()

网口通信控制

2.1 TCP/IP 通信

C# TCP 客户端实现
csharp 复制代码
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace IndustrialAutomation.Network
{
    public class TcpClientManager : IDisposable
    {
        private TcpClient _client;
        private NetworkStream _stream;
        private bool _isConnected;
        private CancellationTokenSource _cancellationTokenSource;
        
        public event EventHandler<byte[]> DataReceived;
        public event EventHandler<Exception> ErrorOccurred;
        public event EventHandler Connected;
        public event EventHandler Disconnected;
        
        public string ServerIP { get; private set; }
        public int ServerPort { get; private set; }
        public bool IsConnected => _isConnected && _client?.Connected == true;
        
        public TcpClientManager(string serverIP, int serverPort)
        {
            ServerIP = serverIP;
            ServerPort = serverPort;
        }
        
        /// <summary>
        /// 异步连接到服务器
        /// </summary>
        public async Task<bool> ConnectAsync(int timeout = 5000)
        {
            try
            {
                _client = new TcpClient();
                var connectTask = _client.ConnectAsync(ServerIP, ServerPort);
                
                if (await Task.WhenAny(connectTask, Task.Delay(timeout)) == connectTask)
                {
                    _stream = _client.GetStream();
                    _isConnected = true;
                    _cancellationTokenSource = new CancellationTokenSource();
                    
                    // 启动接收线程
                    _ = Task.Run(() => ReceiveDataAsync(_cancellationTokenSource.Token));
                    
                    Connected?.Invoke(this, EventArgs.Empty);
                    Console.WriteLine($"已连接到 {ServerIP}:{ServerPort}");
                    return true;
                }
                else
                {
                    throw new TimeoutException("连接超时");
                }
            }
            catch (Exception ex)
            {
                ErrorOccurred?.Invoke(this, ex);
                return false;
            }
        }
        
        /// <summary>
        /// 发送数据
        /// </summary>
        public async Task<bool> SendAsync(byte[] data)
        {
            try
            {
                if (_stream != null && _stream.CanWrite)
                {
                    await _stream.WriteAsync(data, 0, data.Length);
                    await _stream.FlushAsync();
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                ErrorOccurred?.Invoke(this, ex);
                return false;
            }
        }
        
        /// <summary>
        /// 发送字符串
        /// </summary>
        public Task<bool> SendStringAsync(string message, Encoding encoding = null)
        {
            encoding = encoding ?? Encoding.UTF8;
            byte[] data = encoding.GetBytes(message);
            return SendAsync(data);
        }
        
        /// <summary>
        /// 发送并等待响应
        /// </summary>
        public async Task<byte[]> SendAndReceiveAsync(byte[] data, int expectedLength, int timeout = 3000)
        {
            try
            {
                if (!IsConnected) return null;
                
                await SendAsync(data);
                
                byte[] buffer = new byte[expectedLength];
                var readTask = _stream.ReadAsync(buffer, 0, expectedLength);
                
                if (await Task.WhenAny(readTask, Task.Delay(timeout)) == readTask)
                {
                    int bytesRead = await readTask;
                    if (bytesRead == expectedLength)
                        return buffer;
                }
                
                return null;
            }
            catch (Exception ex)
            {
                ErrorOccurred?.Invoke(this, ex);
                return null;
            }
        }
        
        private async Task ReceiveDataAsync(CancellationToken token)
        {
            byte[] buffer = new byte[4096];
            
            try
            {
                while (!token.IsCancellationRequested && _stream != null)
                {
                    int bytesRead = await _stream.ReadAsync(buffer, 0, buffer.Length, token);
                    
                    if (bytesRead > 0)
                    {
                        byte[] data = new byte[bytesRead];
                        Array.Copy(buffer, data, bytesRead);
                        DataReceived?.Invoke(this, data);
                    }
                    else
                    {
                        // 连接已断开
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                if (!token.IsCancellationRequested)
                    ErrorOccurred?.Invoke(this, ex);
            }
            finally
            {
                Disconnect();
            }
        }
        
        public void Disconnect()
        {
            _isConnected = false;
            _cancellationTokenSource?.Cancel();
            _stream?.Close();
            _client?.Close();
            Disconnected?.Invoke(this, EventArgs.Empty);
            Console.WriteLine("连接已断开");
        }
        
        public void Dispose()
        {
            Disconnect();
            _cancellationTokenSource?.Dispose();
            _stream?.Dispose();
            _client?.Dispose();
        }
    }
}
C# TCP 服务器实现
csharp 复制代码
using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace IndustrialAutomation.Network
{
    public class TcpServerManager : IDisposable
    {
        private TcpListener _listener;
        private CancellationTokenSource _cancellationTokenSource;
        private ConcurrentDictionary<string, TcpClient> _clients;
        
        public event EventHandler<ClientConnectedEventArgs> ClientConnected;
        public event EventHandler<ClientDisconnectedEventArgs> ClientDisconnected;
        public event EventHandler<DataReceivedEventArgs> DataReceived;
        
        public int Port { get; private set; }
        public bool IsRunning { get; private set; }
        
        public TcpServerManager(int port)
        {
            Port = port;
            _clients = new ConcurrentDictionary<string, TcpClient>();
        }
        
        public void Start()
        {
            try
            {
                _listener = new TcpListener(IPAddress.Any, Port);
                _listener.Start();
                _cancellationTokenSource = new CancellationTokenSource();
                IsRunning = true;
                
                _ = Task.Run(() => AcceptClientsAsync(_cancellationTokenSource.Token));
                Console.WriteLine($"TCP服务器已启动,监听端口: {Port}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"启动服务器失败: {ex.Message}");
            }
        }
        
        private async Task AcceptClientsAsync(CancellationToken token)
        {
            while (!token.IsCancellationRequested)
            {
                try
                {
                    TcpClient client = await _listener.AcceptTcpClientAsync();
                    string clientId = client.Client.RemoteEndPoint.ToString();
                    
                    _clients.TryAdd(clientId, client);
                    ClientConnected?.Invoke(this, new ClientConnectedEventArgs(clientId));
                    
                    _ = Task.Run(() => HandleClientAsync(client, clientId, token));
                }
                catch (Exception ex)
                {
                    if (!token.IsCancellationRequested)
                        Console.WriteLine($"接受客户端连接失败: {ex.Message}");
                }
            }
        }
        
        private async Task HandleClientAsync(TcpClient client, string clientId, CancellationToken token)
        {
            NetworkStream stream = client.GetStream();
            byte[] buffer = new byte[4096];
            
            try
            {
                while (!token.IsCancellationRequested && client.Connected)
                {
                    int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token);
                    
                    if (bytesRead > 0)
                    {
                        byte[] data = new byte[bytesRead];
                        Array.Copy(buffer, data, bytesRead);
                        DataReceived?.Invoke(this, new DataReceivedEventArgs(clientId, data));
                    }
                    else
                    {
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"处理客户端数据失败: {ex.Message}");
            }
            finally
            {
                _clients.TryRemove(clientId, out _);
                stream.Close();
                client.Close();
                ClientDisconnected?.Invoke(this, new ClientDisconnectedEventArgs(clientId));
            }
        }
        
        public async Task<bool> SendToClientAsync(string clientId, byte[] data)
        {
            if (_clients.TryGetValue(clientId, out TcpClient client))
            {
                try
                {
                    NetworkStream stream = client.GetStream();
                    await stream.WriteAsync(data, 0, data.Length);
                    return true;
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"发送数据失败: {ex.Message}");
                }
            }
            return false;
        }
        
        public async Task BroadcastAsync(byte[] data)
        {
            foreach (var client in _clients.Values)
            {
                try
                {
                    NetworkStream stream = client.GetStream();
                    await stream.WriteAsync(data, 0, data.Length);
                }
                catch { }
            }
        }
        
        public void Stop()
        {
            IsRunning = false;
            _cancellationTokenSource?.Cancel();
            
            foreach (var client in _clients.Values)
            {
                client.Close();
            }
            
            _clients.Clear();
            _listener?.Stop();
            Console.WriteLine("TCP服务器已停止");
        }
        
        public void Dispose()
        {
            Stop();
            _cancellationTokenSource?.Dispose();
        }
    }
    
    public class ClientConnectedEventArgs : EventArgs
    {
        public string ClientId { get; }
        public ClientConnectedEventArgs(string clientId) => ClientId = clientId;
    }
    
    public class ClientDisconnectedEventArgs : EventArgs
    {
        public string ClientId { get; }
        public ClientDisconnectedEventArgs(string clientId) => ClientId = clientId;
    }
    
    public class DataReceivedEventArgs : EventArgs
    {
        public string ClientId { get; }
        public byte[] Data { get; }
        public DataReceivedEventArgs(string clientId, byte[] data)
        {
            ClientId = clientId;
            Data = data;
        }
    }
}
Python TCP 通信实现
python 复制代码
import socket
import threading
import time
from typing import Optional, Callable, Dict
from queue import Queue

class TcpClient:
    """TCP客户端"""
    
    def __init__(self, host: str, port: int, buffer_size: int = 4096):
        self.host = host
        self.port = port
        self.buffer_size = buffer_size
        self.socket: Optional[socket.socket] = None
        self.is_connected = False
        self.receive_thread: Optional[threading.Thread] = None
        self.running = False
        
        # 回调函数
        self.on_data_received: Optional[Callable[[bytes], None]] = None
        self.on_connected: Optional[Callable[[], None]] = None
        self.on_disconnected: Optional[Callable[[], None]] = None
        self.on_error: Optional[Callable[[Exception], None]] = None
    
    def connect(self, timeout: float = 5.0) -> bool:
        """连接到服务器"""
        try:
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.socket.settimeout(timeout)
            self.socket.connect((self.host, self.port))
            self.socket.settimeout(None)
            
            self.is_connected = True
            self.running = True
            
            # 启动接收线程
            self.receive_thread = threading.Thread(target=self._receive_loop, daemon=True)
            self.receive_thread.start()
            
            print(f"已连接到 {self.host}:{self.port}")
            if self.on_connected:
                self.on_connected()
            
            return True
        except Exception as e:
            print(f"连接失败: {e}")
            if self.on_error:
                self.on_error(e)
            return False
    
    def disconnect(self):
        """断开连接"""
        self.running = False
        self.is_connected = False
        
        if self.socket:
            try:
                self.socket.close()
            except:
                pass
        
        if self.receive_thread and self.receive_thread.is_alive():
            self.receive_thread.join(timeout=2)
        
        print("连接已断开")
        if self.on_disconnected:
            self.on_disconnected()
    
    def send(self, data: bytes) -> bool:
        """发送数据"""
        try:
            if self.socket and self.is_connected:
                self.socket.sendall(data)
                return True
            return False
        except Exception as e:
            print(f"发送数据失败: {e}")
            if self.on_error:
                self.on_error(e)
            self.disconnect()
            return False
    
    def send_string(self, message: str, encoding: str = 'utf-8') -> bool:
        """发送字符串"""
        return self.send(message.encode(encoding))
    
    def send_and_receive(self, data: bytes, timeout: float = 3.0) -> Optional[bytes]:
        """发送数据并等待响应"""
        try:
            if not self.is_connected:
                return None
            
            self.socket.settimeout(timeout)
            self.socket.sendall(data)
            
            response = self.socket.recv(self.buffer_size)
            self.socket.settimeout(None)
            
            return response if response else None
        except socket.timeout:
            print("接收超时")
            self.socket.settimeout(None)
            return None
        except Exception as e:
            print(f"通信失败: {e}")
            if self.on_error:
                self.on_error(e)
            return None
    
    def _receive_loop(self):
        """接收数据循环"""
        while self.running:
            try:
                data = self.socket.recv(self.buffer_size)
                if data:
                    if self.on_data_received:
                        self.on_data_received(data)
                else:
                    # 连接已关闭
                    break
            except Exception as e:
                if self.running:
                    print(f"接收数据错误: {e}")
                    if self.on_error:
                        self.on_error(e)
                break
        
        self.disconnect()
    
    def __enter__(self):
        self.connect()
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.disconnect()


class TcpServer:
    """TCP服务器"""
    
    def __init__(self, host: str = '0.0.0.0', port: int = 8888, buffer_size: int = 4096):
        self.host = host
        self.port = port
        self.buffer_size = buffer_size
        self.server_socket: Optional[socket.socket] = None
        self.clients: Dict[str, socket.socket] = {}
        self.running = False
        
        # 回调函数
        self.on_client_connected: Optional[Callable[[str], None]] = None
        self.on_client_disconnected: Optional[Callable[[str], None]] = None
        self.on_data_received: Optional[Callable[[str, bytes], None]] = None
    
    def start(self):
        """启动服务器"""
        try:
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.server_socket.bind((self.host, self.port))
            self.server_socket.listen(5)
            
            self.running = True
            print(f"TCP服务器已启动,监听 {self.host}:{self.port}")
            
            # 启动接受连接的线程
            accept_thread = threading.Thread(target=self._accept_loop, daemon=True)
            accept_thread.start()
            
        except Exception as e:
            print(f"启动服务器失败: {e}")
    
    def stop(self):
        """停止服务器"""
        self.running = False
        
        # 关闭所有客户端连接
        for client_id, client_socket in list(self.clients.items()):
            try:
                client_socket.close()
            except:
                pass
        
        self.clients.clear()
        
        # 关闭服务器套接字
        if self.server_socket:
            try:
                self.server_socket.close()
            except:
                pass
        
        print("TCP服务器已停止")
    
    def _accept_loop(self):
        """接受客户端连接循环"""
        while self.running:
            try:
                client_socket, client_address = self.server_socket.accept()
                client_id = f"{client_address[0]}:{client_address[1]}"
                
                self.clients[client_id] = client_socket
                print(f"客户端已连接: {client_id}")
                
                if self.on_client_connected:
                    self.on_client_connected(client_id)
                
                # 为每个客户端启动处理线程
                client_thread = threading.Thread(
                    target=self._handle_client,
                    args=(client_socket, client_id),
                    daemon=True
                )
                client_thread.start()
                
            except Exception as e:
                if self.running:
                    print(f"接受客户端连接失败: {e}")
    
    def _handle_client(self, client_socket: socket.socket, client_id: str):
        """处理客户端数据"""
        try:
            while self.running:
                data = client_socket.recv(self.buffer_size)
                if data:
                    if self.on_data_received:
                        self.on_data_received(client_id, data)
                else:
                    break
        except Exception as e:
            print(f"处理客户端数据失败: {e}")
        finally:
            # 清理客户端
            if client_id in self.clients:
                del self.clients[client_id]
            
            try:
                client_socket.close()
            except:
                pass
            
            print(f"客户端已断开: {client_id}")
            if self.on_client_disconnected:
                self.on_client_disconnected(client_id)
    
    def send_to_client(self, client_id: str, data: bytes) -> bool:
        """发送数据到指定客户端"""
        if client_id in self.clients:
            try:
                self.clients[client_id].sendall(data)
                return True
            except Exception as e:
                print(f"发送数据失败: {e}")
                return False
        return False
    
    def broadcast(self, data: bytes):
        """广播数据到所有客户端"""
        for client_id, client_socket in list(self.clients.items()):
            try:
                client_socket.sendall(data)
            except:
                pass

2.2 UDP 通信实现

Python UDP 实现
python 复制代码
import socket
import threading
from typing import Optional, Callable, Tuple

class UdpCommunicator:
    """UDP通信器(可用作客户端或服务器)"""
    
    def __init__(self, local_port: int = 0, buffer_size: int = 4096):
        """
        初始化UDP通信器
        
        Args:
            local_port: 本地绑定端口,0表示自动分配
            buffer_size: 接收缓冲区大小
        """
        self.local_port = local_port
        self.buffer_size = buffer_size
        self.socket: Optional[socket.socket] = None
        self.running = False
        self.receive_thread: Optional[threading.Thread] = None
        
        # 回调函数
        self.on_data_received: Optional[Callable[[bytes, Tuple[str, int]], None]] = None
    
    def start(self):
        """启动UDP通信"""
        try:
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.socket.bind(('0.0.0.0', self.local_port))
            
            # 获取实际绑定的端口
            self.local_port = self.socket.getsockname()[1]
            
            self.running = True
            self.receive_thread = threading.Thread(target=self._receive_loop, daemon=True)
            self.receive_thread.start()
            
            print(f"UDP通信已启动,监听端口: {self.local_port}")
        except Exception as e:
            print(f"启动UDP通信失败: {e}")
    
    def stop(self):
        """停止UDP通信"""
        self.running = False
        
        if self.socket:
            try:
                self.socket.close()
            except:
                pass
        
        if self.receive_thread and self.receive_thread.is_alive():
            self.receive_thread.join(timeout=2)
        
        print("UDP通信已停止")
    
    def send(self, data: bytes, address: Tuple[str, int]) -> bool:
        """
        发送数据
        
        Args:
            data: 要发送的数据
            address: 目标地址 (host, port)
        """
        try:
            if self.socket:
                self.socket.sendto(data, address)
                return True
            return False
        except Exception as e:
            print(f"发送UDP数据失败: {e}")
            return False
    
    def send_string(self, message: str, address: Tuple[str, int], encoding: str = 'utf-8') -> bool:
        """发送字符串"""
        return self.send(message.encode(encoding), address)
    
    def send_broadcast(self, data: bytes, port: int):
        """发送广播消息"""
        try:
            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
            self.socket.sendto(data, ('<broadcast>', port))
            return True
        except Exception as e:
            print(f"发送广播失败: {e}")
            return False
    
    def _receive_loop(self):
        """接收数据循环"""
        while self.running:
            try:
                data, address = self.socket.recvfrom(self.buffer_size)
                if self.on_data_received:
                    self.on_data_received(data, address)
            except Exception as e:
                if self.running:
                    print(f"接收UDP数据错误: {e}")
    
    def __enter__(self):
        self.start()
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.stop()

2.3 Modbus TCP 实现

python 复制代码
import struct
from typing import Optional, List

class ModbusTCP:
    """Modbus TCP协议实现"""
    
    def __init__(self, host: str, port: int = 502):
        self.tcp_client = TcpClient(host, port)
        self.transaction_id = 0
    
    def connect(self) -> bool:
        return self.tcp_client.connect()
    
    def disconnect(self):
        self.tcp_client.disconnect()
    
    def read_holding_registers(self, slave_id: int, start_address: int, quantity: int) -> Optional[List[int]]:
        """读取保持寄存器"""
        self.transaction_id += 1
        
        # 构建Modbus TCP请求
        request = struct.pack('>HHHBBHH',
            self.transaction_id,  # 事务标识符
            0,                    # 协议标识符
            6,                    # 长度
            slave_id,             # 单元标识符
            0x03,                 # 功能码
            start_address,        # 起始地址
            quantity              # 数量
        )
        
        # 发送并接收
        response = self.tcp_client.send_and_receive(request, timeout=3.0)
        
        if not response or len(response) < 9:
            return None
        
        # 解析响应
        trans_id, proto_id, length, unit_id, func_code, byte_count = struct.unpack('>HHHBBB', response[:9])
        
        if func_code != 0x03 or trans_id != self.transaction_id:
            return None
        
        # 提取寄存器值
        values = []
        for i in range(quantity):
            offset = 9 + (i * 2)
            if offset + 2 <= len(response):
                value = struct.unpack('>H', response[offset:offset+2])[0]
                values.append(value)
        
        return values
    
    def write_single_register(self, slave_id: int, address: int, value: int) -> bool:
        """写单个寄存器"""
        self.transaction_id += 1
        
        request = struct.pack('>HHHBBHH',
            self.transaction_id,
            0,
            6,
            slave_id,
            0x06,
            address,
            value
        )
        
        response = self.tcp_client.send_and_receive(request, timeout=3.0)
        return response is not None and len(response) >= 12
    
    def write_multiple_registers(self, slave_id: int, start_address: int, values: List[int]) -> bool:
        """写多个寄存器"""
        self.transaction_id += 1
        quantity = len(values)
        byte_count = quantity * 2
        
        # 构建请求头
        request = struct.pack('>HHHBBHHB',
            self.transaction_id,
            0,
            7 + byte_count,
            slave_id,
            0x10,
            start_address,
            quantity,
            byte_count
        )
        
        # 添加数据
        for value in values:
            request += struct.pack('>H', value)
        
        response = self.tcp_client.send_and_receive(request, timeout=3.0)
        return response is not None and len(response) >= 12

物联网控制

3.1 MQTT 协议实现

C# MQTT 客户端(使用MQTTnet库)
csharp 复制代码
using MQTTnet;
using MQTTnet.Client;
using System;
using System.Text;
using System.Threading.Tasks;

namespace IndustrialAutomation.IoT
{
    public class MqttClientManager : IDisposable
    {
        private IMqttClient _mqttClient;
        private MqttClientOptions _options;
        
        public event EventHandler<string> MessageReceived;
        public event EventHandler Connected;
        public event EventHandler Disconnected;
        
        public bool IsConnected => _mqttClient?.IsConnected ?? false;
        
        public MqttClientManager(string broker, int port = 1883, string clientId = null)
        {
            var factory = new MqttFactory();
            _mqttClient = factory.CreateMqttClient();
            
            clientId = clientId ?? $"Client_{Guid.NewGuid():N}";
            
            _options = new MqttClientOptionsBuilder()
                .WithTcpServer(broker, port)
                .WithClientId(clientId)
                .WithCleanSession()
                .Build();
            
            _mqttClient.ConnectedAsync += OnConnectedAsync;
            _mqttClient.DisconnectedAsync += OnDisconnectedAsync;
            _mqttClient.ApplicationMessageReceivedAsync += OnMessageReceivedAsync;
        }
        
        public async Task<bool> ConnectAsync(string username = null, string password = null)
        {
            try
            {
                if (!string.IsNullOrEmpty(username))
                {
                    _options = new MqttClientOptionsBuilder(_options)
                        .WithCredentials(username, password)
                        .Build();
                }
                
                await _mqttClient.ConnectAsync(_options);
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"MQTT连接失败: {ex.Message}");
                return false;
            }
        }
        
        public async Task DisconnectAsync()
        {
            if (_mqttClient.IsConnected)
            {
                await _mqttClient.DisconnectAsync();
            }
        }
        
        public async Task<bool> SubscribeAsync(string topic, int qos = 1)
        {
            try
            {
                var subscribeOptions = new MqttClientSubscribeOptionsBuilder()
                    .WithTopicFilter(f => f.WithTopic(topic).WithQualityOfServiceLevel((MQTTnet.Protocol.MqttQualityOfServiceLevel)qos))
                    .Build();
                
                await _mqttClient.SubscribeAsync(subscribeOptions);
                Console.WriteLine($"已订阅主题: {topic}");
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"订阅失败: {ex.Message}");
                return false;
            }
        }
        
        public async Task<bool> UnsubscribeAsync(string topic)
        {
            try
            {
                var unsubscribeOptions = new MqttClientUnsubscribeOptionsBuilder()
                    .WithTopicFilter(topic)
                    .Build();
                
                await _mqttClient.UnsubscribeAsync(unsubscribeOptions);
                Console.WriteLine($"已取消订阅: {topic}");
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"取消订阅失败: {ex.Message}");
                return false;
            }
        }
        
        public async Task<bool> PublishAsync(string topic, string payload, int qos = 1, bool retain = false)
        {
            try
            {
                var message = new MqttApplicationMessageBuilder()
                    .WithTopic(topic)
                    .WithPayload(payload)
                    .WithQualityOfServiceLevel((MQTTnet.Protocol.MqttQualityOfServiceLevel)qos)
                    .WithRetainFlag(retain)
                    .Build();
                
                await _mqttClient.PublishAsync(message);
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"发布消息失败: {ex.Message}");
                return false;
            }
        }
        
        public async Task<bool> PublishJsonAsync<T>(string topic, T data, int qos = 1)
        {
            string json = System.Text.Json.JsonSerializer.Serialize(data);
            return await PublishAsync(topic, json, qos);
        }
        
        private Task OnConnectedAsync(MqttClientConnectedEventArgs arg)
        {
            Console.WriteLine("MQTT已连接");
            Connected?.Invoke(this, EventArgs.Empty);
            return Task.CompletedTask;
        }
        
        private Task OnDisconnectedAsync(MqttClientDisconnectedEventArgs arg)
        {
            Console.WriteLine("MQTT已断开");
            Disconnected?.Invoke(this, EventArgs.Empty);
            return Task.CompletedTask;
        }
        
        private Task OnMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg)
        {
            string payload = Encoding.UTF8.GetString(arg.ApplicationMessage.PayloadSegment);
            string topic = arg.ApplicationMessage.Topic;
            
            Console.WriteLine($"收到消息 - 主题: {topic}, 内容: {payload}");
            MessageReceived?.Invoke(this, payload);
            
            return Task.CompletedTask;
        }
        
        public void Dispose()
        {
            _mqttClient?.Dispose();
        }
    }
}
Python MQTT 客户端(使用paho-mqtt库)
python 复制代码
import paho.mqtt.client as mqtt
import json
from typing import Optional, Callable, Any
import time

class MqttClient:
    """MQTT客户端封装"""
    
    def __init__(self, broker: str, port: int = 1883, client_id: Optional[str] = None):
        """
        初始化MQTT客户端
        
        Args:
            broker: MQTT代理服务器地址
            port: 端口号
            client_id: 客户端ID,None则自动生成
        """
        self.broker = broker
        self.port = port
        self.client_id = client_id or f"client_{int(time.time())}"
        
        self.client = mqtt.Client(client_id=self.client_id)
        self.is_connected = False
        
        # 设置回调
        self.client.on_connect = self._on_connect
        self.client.on_disconnect = self._on_disconnect
        self.client.on_message = self._on_message
        self.client.on_subscribe = self._on_subscribe
        self.client.on_publish = self._on_publish
        
        # 用户回调函数
        self.on_message_callback: Optional[Callable[[str, str], None]] = None
        self.on_connected_callback: Optional[Callable[[], None]] = None
        self.on_disconnected_callback: Optional[Callable[[], None]] = None
    
    def connect(self, username: Optional[str] = None, password: Optional[str] = None, 
                keepalive: int = 60) -> bool:
        """连接到MQTT代理"""
        try:
            if username and password:
                self.client.username_pw_set(username, password)
            
            self.client.connect(self.broker, self.port, keepalive)
            self.client.loop_start()  # 启动网络循环
            
            # 等待连接建立
            timeout = 10
            start_time = time.time()
            while not self.is_connected and (time.time() - start_time) < timeout:
                time.sleep(0.1)
            
            return self.is_connected
        except Exception as e:
            print(f"MQTT连接失败: {e}")
            return False
    
    def disconnect(self):
        """断开连接"""
        self.client.loop_stop()
        self.client.disconnect()
    
    def subscribe(self, topic: str, qos: int = 1):
        """订阅主题"""
        self.client.subscribe(topic, qos)
        print(f"已订阅主题: {topic}")
    
    def unsubscribe(self, topic: str):
        """取消订阅"""
        self.client.unsubscribe(topic)
        print(f"已取消订阅: {topic}")
    
    def publish(self, topic: str, payload: str, qos: int = 1, retain: bool = False) -> bool:
        """发布消息"""
        try:
            result = self.client.publish(topic, payload, qos, retain)
            return result.rc == mqtt.MQTT_ERR_SUCCESS
        except Exception as e:
            print(f"发布消息失败: {e}")
            return False
    
    def publish_json(self, topic: str, data: Any, qos: int = 1, retain: bool = False) -> bool:
        """发布JSON数据"""
        try:
            payload = json.dumps(data, ensure_ascii=False)
            return self.publish(topic, payload, qos, retain)
        except Exception as e:
            print(f"发布JSON失败: {e}")
            return False
    
    def _on_connect(self, client, userdata, flags, rc):
        """连接回调"""
        if rc == 0:
            self.is_connected = True
            print("MQTT已连接")
            if self.on_connected_callback:
                self.on_connected_callback()
        else:
            print(f"MQTT连接失败,错误码: {rc}")
    
    def _on_disconnect(self, client, userdata, rc):
        """断开连接回调"""
        self.is_connected = False
        print("MQTT已断开")
        if self.on_disconnected_callback:
            self.on_disconnected_callback()
    
    def _on_message(self, client, userdata, msg):
        """消息接收回调"""
        topic = msg.topic
        payload = msg.payload.decode('utf-8')
        print(f"收到消息 - 主题: {topic}, 内容: {payload}")
        
        if self.on_message_callback:
            self.on_message_callback(topic, payload)
    
    def _on_subscribe(self, client, userdata, mid, granted_qos):
        """订阅确认回调"""
        print(f"订阅确认,QoS: {granted_qos}")
    
    def _on_publish(self, client, userdata, mid):
        """发布确认回调"""
        pass
    
    def __enter__(self):
        self.connect()
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.disconnect()

3.2 HTTP RESTful API 实现

Python HTTP客户端(用于物联网平台API)
python 复制代码
import requests
import json
from typing import Optional, Dict, Any
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

class IoTApiClient:
    """物联网平台HTTP API客户端"""
    
    def __init__(self, base_url: str, api_key: Optional[str] = None, timeout: int = 30):
        """
        初始化API客户端
        
        Args:
            base_url: API基础URL
            api_key: API密钥
            timeout: 请求超时时间
        """
        self.base_url = base_url.rstrip('/')
        self.api_key = api_key
        self.timeout = timeout
        
        # 创建会话
        self.session = requests.Session()
        
        # 设置重试策略
        retry_strategy = Retry(
            total=3,
            backoff_factor=1,
            status_forcelist=[429, 500, 502, 503, 504],
            allowed_methods=["HEAD", "GET", "OPTIONS", "POST", "PUT", "DELETE"]
        )
        adapter = HTTPAdapter(max_retries=retry_strategy)
        self.session.mount("http://", adapter)
        self.session.mount("https://", adapter)
        
        # 设置默认请求头
        self.session.headers.update({
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        })
        
        if api_key:
            self.session.headers.update({'Authorization': f'Bearer {api_key}'})
    
    def get(self, endpoint: str, params: Optional[Dict] = None) -> Optional[Dict]:
        """GET请求"""
        try:
            url = f"{self.base_url}/{endpoint.lstrip('/')}"
            response = self.session.get(url, params=params, timeout=self.timeout)
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            print(f"GET请求失败: {e}")
            return None
    
    def post(self, endpoint: str, data: Optional[Dict] = None) -> Optional[Dict]:
        """POST请求"""
        try:
            url = f"{self.base_url}/{endpoint.lstrip('/')}"
            response = self.session.post(url, json=data, timeout=self.timeout)
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            print(f"POST请求失败: {e}")
            return None
    
    def put(self, endpoint: str, data: Optional[Dict] = None) -> Optional[Dict]:
        """PUT请求"""
        try:
            url = f"{self.base_url}/{endpoint.lstrip('/')}"
            response = self.session.put(url, json=data, timeout=self.timeout)
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            print(f"PUT请求失败: {e}")
            return None
    
    def delete(self, endpoint: str) -> bool:
        """DELETE请求"""
        try:
            url = f"{self.base_url}/{endpoint.lstrip('/')}"
            response = self.session.delete(url, timeout=self.timeout)
            response.raise_for_status()
            return True
        except requests.exceptions.RequestException as e:
            print(f"DELETE请求失败: {e}")
            return False
    
    # 设备管理API示例
    def get_device(self, device_id: str) -> Optional[Dict]:
        """获取设备信息"""
        return self.get(f"/devices/{device_id}")
    
    def get_devices(self, page: int = 1, page_size: int = 20) -> Optional[Dict]:
        """获取设备列表"""
        return self.get("/devices", params={"page": page, "pageSize": page_size})
    
    def create_device(self, device_data: Dict) -> Optional[Dict]:
        """创建设备"""
        return self.post("/devices", data=device_data)
    
    def update_device(self, device_id: str, device_data: Dict) -> Optional[Dict]:
        """更新设备"""
        return self.put(f"/devices/{device_id}", data=device_data)
    
    def delete_device(self, device_id: str) -> bool:
        """删除设备"""
        return self.delete(f"/devices/{device_id}")
    
    def send_command(self, device_id: str, command: str, params: Optional[Dict] = None) -> Optional[Dict]:
        """向设备发送命令"""
        data = {
            "command": command,
            "params": params or {}
        }
        return self.post(f"/devices/{device_id}/commands", data=data)
    
    def get_telemetry(self, device_id: str, start_time: Optional[str] = None, 
                     end_time: Optional[str] = None) -> Optional[Dict]:
        """获取设备遥测数据"""
        params = {}
        if start_time:
            params['startTime'] = start_time
        if end_time:
            params['endTime'] = end_time
        
        return self.get(f"/devices/{device_id}/telemetry", params=params)

综合应用案例

4.1 智能工厂数据采集系统

python 复制代码
import threading
import time
import queue
from datetime import datetime
from typing import Dict, List

class IndustrialDataCollector:
    """工业数据采集器 - 综合串口、网口、物联网"""
    
    def __init__(self):
        # 数据队列
        self.data_queue = queue.Queue()
        
        # 通信管理器
        self.modbus_rtu = None
        self.modbus_tcp = None
        self.mqtt_client = None
        self.api_client = None
        
        # 运行状态
        self.running = False
        self.threads: List[threading.Thread] = []
    
    def initialize(self, config: Dict):
        """初始化所有通信接口"""
        # 初始化Modbus RTU(串口)
        if 'modbus_rtu' in config:
            cfg = config['modbus_rtu']
            self.modbus_rtu = ModbusRTU(cfg['port'], cfg['baudrate'])
            self.modbus_rtu.open()
            print("Modbus RTU已初始化")
        
        # 初始化Modbus TCP(网口)
        if 'modbus_tcp' in config:
            cfg = config['modbus_tcp']
            self.modbus_tcp = ModbusTCP(cfg['host'], cfg['port'])
            self.modbus_tcp.connect()
            print("Modbus TCP已初始化")
        
        # 初始化MQTT(物联网)
        if 'mqtt' in config:
            cfg = config['mqtt']
            self.mqtt_client = MqttClient(cfg['broker'], cfg['port'])
            self.mqtt_client.connect(cfg.get('username'), cfg.get('password'))
            self.mqtt_client.subscribe(cfg['subscribe_topic'])
            
            # 设置MQTT消息回调
            self.mqtt_client.on_message_callback = self._on_mqtt_message
            print("MQTT已初始化")
        
        # 初始化HTTP API(云平台)
        if 'api' in config:
            cfg = config['api']
            self.api_client = IoTApiClient(cfg['base_url'], cfg['api_key'])
            print("API客户端已初始化")
    
    def start(self):
        """启动数据采集"""
        self.running = True
        
        # 启动各个数据采集线程
        if self.modbus_rtu:
            thread = threading.Thread(target=self._collect_modbus_rtu_data, daemon=True)
            thread.start()
            self.threads.append(thread)
        
        if self.modbus_tcp:
            thread = threading.Thread(target=self._collect_modbus_tcp_data, daemon=True)
            thread.start()
            self.threads.append(thread)
        
        # 启动数据处理线程
        thread = threading.Thread(target=self._process_data, daemon=True)
        thread.start()
        self.threads.append(thread)
        
        print("数据采集已启动")
    
    def stop(self):
        """停止数据采集"""
        self.running = False
        
        # 等待线程结束
        for thread in self.threads:
            thread.join(timeout=2)
        
        # 关闭所有连接
        if self.modbus_rtu:
            self.modbus_rtu.close()
        if self.modbus_tcp:
            self.modbus_tcp.disconnect()
        if self.mqtt_client:
            self.mqtt_client.disconnect()
        
        print("数据采集已停止")
    
    def _collect_modbus_rtu_data(self):
        """采集Modbus RTU数据(串口设备)"""
        while self.running:
            try:
                # 读取传感器数据
                values = self.modbus_rtu.read_holding_registers(
                    slave_id=1,
                    start_address=0,
                    quantity=10
                )
                
                if values:
                    data = {
                        'source': 'modbus_rtu',
                        'timestamp': datetime.now().isoformat(),
                        'device_id': 'sensor_001',
                        'data': {
                            'temperature': values[0] / 10.0,
                            'humidity': values[1] / 10.0,
                            'pressure': values[2] / 100.0,
                            # 更多传感器数据...
                        }
                    }
                    self.data_queue.put(data)
                
                time.sleep(1)  # 1秒采集一次
                
            except Exception as e:
                print(f"Modbus RTU采集错误: {e}")
                time.sleep(5)
    
    def _collect_modbus_tcp_data(self):
        """采集Modbus TCP数据(网口PLC)"""
        while self.running:
            try:
                # 读取PLC数据
                values = self.modbus_tcp.read_holding_registers(
                    slave_id=1,
                    start_address=0,
                    quantity=20
                )
                
                if values:
                    data = {
                        'source': 'modbus_tcp',
                        'timestamp': datetime.now().isoformat(),
                        'device_id': 'plc_001',
                        'data': {
                            'motor_speed': values[0],
                            'motor_current': values[1] / 100.0,
                            'production_count': values[2],
                            'alarm_status': values[3],
                            # 更多PLC数据...
                        }
                    }
                    self.data_queue.put(data)
                
                time.sleep(0.5)  # 500ms采集一次
                
            except Exception as e:
                print(f"Modbus TCP采集错误: {e}")
                time.sleep(5)
    
    def _on_mqtt_message(self, topic: str, payload: str):
        """处理MQTT消息"""
        try:
            import json
            message_data = json.loads(payload)
            
            data = {
                'source': 'mqtt',
                'timestamp': datetime.now().isoformat(),
                'topic': topic,
                'data': message_data
            }
            self.data_queue.put(data)
            
        except Exception as e:
            print(f"MQTT消息处理错误: {e}")
    
    def _process_data(self):
        """处理采集的数据"""
        while self.running:
            try:
                # 从队列获取数据(阻塞,超时1秒)
                data = self.data_queue.get(timeout=1)
                
                # 数据处理逻辑
                print(f"处理数据: {data['source']} - {data['device_id'] if 'device_id' in data else data.get('topic', 'N/A')}")
                
                # 1. 本地存储(可选)
                self._store_locally(data)
                
                # 2. 上传到云平台
                if self.api_client:
                    self._upload_to_cloud(data)
                
                # 3. 通过MQTT发布(可选)
                if self.mqtt_client:
                    self._publish_to_mqtt(data)
                
                # 4. 实时分析和告警
                self._analyze_and_alert(data)
                
            except queue.Empty:
                continue
            except Exception as e:
                print(f"数据处理错误: {e}")
    
    def _store_locally(self, data: Dict):
        """本地存储数据"""
        # 这里可以存储到SQLite、CSV等
        pass
    
    def _upload_to_cloud(self, data: Dict):
        """上传数据到云平台"""
        try:
            result = self.api_client.post('/telemetry', data=data)
            if result:
                print(f"数据已上传到云平台")
        except Exception as e:
            print(f"上传云平台失败: {e}")
    
    def _publish_to_mqtt(self, data: Dict):
        """通过MQTT发布数据"""
        try:
            topic = f"factory/data/{data.get('device_id', 'unknown')}"
            self.mqtt_client.publish_json(topic, data)
        except Exception as e:
            print(f"MQTT发布失败: {e}")
    
    def _analyze_and_alert(self, data: Dict):
        """数据分析和告警"""
        # 实现告警逻辑
        if 'data' in data:
            values = data['data']
            
            # 温度告警
            if 'temperature' in values and values['temperature'] > 80:
                print(f"⚠️ 温度告警: {values['temperature']}°C")
                # 发送告警...
            
            # 其他告警逻辑...


# 使用示例
if __name__ == "__main__":
    # 配置
    config = {
        'modbus_rtu': {
            'port': '/dev/ttyUSB0',
            'baudrate': 9600
        },
        'modbus_tcp': {
            'host': '192.168.1.100',
            'port': 502
        },
        'mqtt': {
            'broker': 'mqtt.example.com',
            'port': 1883,
            'username': 'user',
            'password': 'pass',
            'subscribe_topic': 'factory/commands/#'
        },
        'api': {
            'base_url': 'https://api.iot-platform.com',
            'api_key': 'your_api_key_here'
        }
    }
    
    # 创建采集器
    collector = IndustrialDataCollector()
    collector.initialize(config)
    collector.start()
    
    try:
        # 运行采集
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        print("\n正在停止...")
        collector.stop()

最佳实践与故障排查

5.1 通信最佳实践

串口通信
  1. 始终添加超时机制,避免程序挂起
  2. 使用CRC或校验位确保数据完整性
  3. 实现重试机制,处理通信失败
  4. 清空缓冲区,避免旧数据干扰
  5. 使用线程或异步,避免阻塞主程序
网口通信
  1. 使用心跳包保持连接活跃
  2. 实现断线重连机制
  3. 限制并发连接数
  4. 使用连接池提高效率
  5. 设置合理的超时时间
物联网通信
  1. 使用QoS机制保证消息可靠性
  2. 实现消息去重
  3. 压缩大数据,减少带宽
  4. 使用TLS加密保护数据安全
  5. 实现离线缓存,网络恢复后上传

5.2 常见故障排查

串口问题
python 复制代码
# 检查可用串口
ports = SerialPortManager.list_ports()
print("可用串口:", ports)

# 测试串口是否可打开
try:
    with SerialPortManager(port, baudrate) as serial:
        print("串口正常")
except Exception as e:
    print(f"串口错误: {e}")
网络连接问题
python 复制代码
import socket

def check_tcp_connection(host: str, port: int) -> bool:
    """检查TCP连接是否可达"""
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(3)
        result = sock.connect_ex((host, port))
        sock.close()
        return result == 0
    except:
        return False

# 使用
if check_tcp_connection('192.168.1.100', 502):
    print("设备在线")
else:
    print("设备离线或端口不可达")

5.3 性能优化建议

  1. 批量操作: 合并多个读写请求,减少通信次数
  2. 数据缓存: 对不常变化的数据进行缓存
  3. 异步处理: 使用异步I/O提高吞吐量
  4. 连接复用: 保持长连接,避免频繁建立连接
  5. 数据压缩: 对大量数据进行压缩传输

5.4 安全性建议

  1. 加密通信: 使用TLS/SSL加密敏感数据
  2. 身份认证: 实现设备认证和用户认证
  3. 访问控制: 限制设备访问权限
  4. 输入验证: 验证所有输入数据,防止注入攻击
  5. 日志记录: 记录所有关键操作,便于审计

总结

本文档详细介绍了工业自动化领域的三大核心通信技术:

  • 串口控制: RS232/RS485通信、Modbus RTU协议
  • 网口控制: TCP/IP、UDP、Modbus TCP协议
  • 物联网控制: MQTT、HTTP RESTful API

通过C#和Python的完整实现代码,您可以快速构建工业自动化系统。记住:

  • 选择合适的通信方式
  • 实现可靠的错误处理
  • 注重系统的可维护性和扩展性
  • 重视数据安全和通信稳定性
相关推荐
帅帅梓4 小时前
nginx访问控制 用户认证 https
运维·nginx·https
b***25115 小时前
比斯特自动化|为什么焊接18650电池离不开点焊机?
运维·自动化
xgysimida5 小时前
一文搞懂supervisord是什么?
运维·运维开发
做运维的阿瑞5 小时前
从传统Linux部署到容器化:实践对比与工程化指南
linux·运维·服务器
怀旧,6 小时前
【Linux系统编程】2. Linux基本指令(上)
linux·运维·服务器
kunge1v56 小时前
学习爬虫第五天:自动化爬虫
爬虫·python·自动化
m***记6 小时前
Python 自动化办公的 10 大脚本
windows·python·自动化
迎風吹頭髮6 小时前
Linux内核架构浅谈9-Linux内核的开源生态:开发者协作与版本迭代机制
linux·运维·架构
Wang's Blog6 小时前
Linux小课堂: 文件系统结构与核心命令解析
linux·运维·服务器