STM32MP1边缘网关:Linux系统下Modbus转MQTT协议转换实战

文章目录

    • 一、项目背景与技术架构
      • [1.1 核心技术栈](#1.1 核心技术栈)
      • [1.2 整体流程架构](#1.2 整体流程架构)
    • 二、环境准备(零基础适配)
      • [2.1 STM32MP1 Linux系统基础配置](#2.1 STM32MP1 Linux系统基础配置)
      • [2.2 安装Modbus与MQTT核心库](#2.2 安装Modbus与MQTT核心库)
      • [2.3 硬件连接确认](#2.3 硬件连接确认)
    • 三、核心功能开发(分模块实现)
      • [3.1 Modbus数据读取模块(支持RTU/TCP双模式)](#3.1 Modbus数据读取模块(支持RTU/TCP双模式))
      • [3.2 MQTT数据发布模块](#3.2 MQTT数据发布模块)
      • [3.3 主程序(协议转换整合)](#3.3 主程序(协议转换整合))
    • 四、配置与运行(零基础操作步骤)
      • [4.1 配置文件修改](#4.1 配置文件修改)
      • [4.2 串口权限配置(RTU模式必做)](#4.2 串口权限配置(RTU模式必做))
      • [4.3 运行网关程序](#4.3 运行网关程序)
      • [4.4 后台运行](#4.4 后台运行)
    • 五、调试与验证
      • [5.1 日志查看](#5.1 日志查看)
      • [5.2 MQTT数据验证](#5.2 MQTT数据验证)
      • [5.3 常见问题排查](#5.3 常见问题排查)
    • 六、开机自启配置

一、项目背景与技术架构

在工业物联网(IIoT)场景中,大量传统工业设备通过Modbus RTU/TCP协议进行数据交互,而物联网平台普遍采用MQTT协议实现设备接入与数据传输。STM32MP1作为ST推出的异构多核边缘计算芯片,集成Cortex-A7(运行Linux)和Cortex-M4内核,非常适合作为边缘网关实现Modbus与MQTT的协议转换。

1.1 核心技术栈

  • 硬件:STM32MP157开发板(已烧录Linux系统,推荐Debian/Ubuntu)
  • 软件环境:Linux内核5.4+、gcc编译器、Python3.8+
  • 关键库:
    • pymodbus:实现Modbus协议的读写操作
    • paho-mqtt:实现MQTT客户端的连接与数据收发
    • serial:处理串口(Modbus RTU)通信

1.2 整体流程架构

以下是Modbus转MQTT的完整数据流转流程,流程图采用深色底、白色字体,保证视觉清晰:
Modbus寄存器值
工业设备 (Modbus RTU/TCP)
STM32MP1串口/网口 数据接收
Modbus协议解析 数据校验
数据格式转换
JSON格式封装
MQTT客户端连接 物联网平台
MQTT主题发布 转换后数据
物联网平台接收 数据存储/展示
数据解析失败 日志记录
重试/报警

二、环境准备(零基础适配)

2.1 STM32MP1 Linux系统基础配置

  1. 确认开发板网络连通性

    bash 复制代码
    # 查看网卡信息
    ifconfig
    # 配置静态IP(以eth0为例)
    sudo ifconfig eth0 192.168.1.100 netmask 255.255.255.0
    # 设置网关
    sudo route add default gw 192.168.1.1
    # 配置DNS
    sudo echo "nameserver 8.8.8.8" >> /etc/resolv.conf
  2. 更新系统源并安装基础依赖

    bash 复制代码
    # 更新软件包列表
    sudo apt update
    # 安装编译器、Python3及pip
    sudo apt install -y gcc python3 python3-pip python3-dev
    # 安装串口依赖
    sudo apt install -y python3-serial

2.2 安装Modbus与MQTT核心库

bash 复制代码
# 安装pymodbus(支持Modbus RTU/TCP)
pip3 install pymodbus==2.5.3
# 安装paho-mqtt(MQTT客户端)
pip3 install paho-mqtt==1.6.1
# 安装json处理库(系统默认自带,此处确保版本)
pip3 install simplejson==3.19.1

2.3 硬件连接确认

  • Modbus RTU:将工业设备的RS485接口通过RS485转TTL模块连接到STM32MP1的UART串口(如/dev/ttySTM0)
  • Modbus TCP:通过网口直连工业设备或交换机
  • 网络:确保STM32MP1能访问MQTT服务器(本地/云端)

三、核心功能开发(分模块实现)

3.1 Modbus数据读取模块(支持RTU/TCP双模式)

创建modbus_reader.py文件,实现Modbus数据的通用读取功能:

python 复制代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Modbus数据读取模块
支持RTU和TCP两种模式
"""
import logging
from pymodbus.client import ModbusSerialClient, ModbusTcpClient
from pymodbus.payload import BinaryPayloadDecoder
from pymodbus.constants import Endian

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('modbus_reader.log', encoding='utf-8'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger('ModbusReader')

class ModbusReader:
    def __init__(self, mode, **kwargs):
        """
        初始化Modbus客户端
        :param mode: 模式 'rtu' 或 'tcp'
        :param kwargs: 连接参数
            RTU参数:port, baudrate, parity, stopbits, bytesize, timeout
            TCP参数:host, port, timeout
        """
        self.mode = mode.lower()
        self.client = None
        self.connected = False
        self.kwargs = kwargs
        self._init_client()

    def _init_client(self):
        """初始化客户端连接"""
        try:
            if self.mode == 'rtu':
                # RTU模式参数配置
                self.client = ModbusSerialClient(
                    port=self.kwargs.get('port', '/dev/ttySTM0'),
                    baudrate=self.kwargs.get('baudrate', 9600),
                    parity=self.kwargs.get('parity', 'N'),
                    stopbits=self.kwargs.get('stopbits', 1),
                    bytesize=self.kwargs.get('bytesize', 8),
                    timeout=self.kwargs.get('timeout', 3)
                )
            elif self.mode == 'tcp':
                # TCP模式参数配置
                self.client = ModbusTcpClient(
                    host=self.kwargs.get('host', '192.168.1.200'),
                    port=self.kwargs.get('port', 502),
                    timeout=self.kwargs.get('timeout', 3)
                )
            else:
                raise ValueError(f"不支持的Modbus模式:{self.mode}")
            logger.info(f"Modbus {self.mode}客户端初始化完成")
        except Exception as e:
            logger.error(f"Modbus客户端初始化失败:{str(e)}")
            raise

    def connect(self):
        """建立Modbus连接"""
        try:
            if self.client.connect():
                self.connected = True
                logger.info(f"Modbus {self.mode}连接成功")
                return True
            else:
                self.connected = False
                logger.error(f"Modbus {self.mode}连接失败")
                return False
        except Exception as e:
            logger.error(f"Modbus连接异常:{str(e)}")
            self.connected = False
            return False

    def read_holding_registers(self, address, count, unit=1):
        """
        读取保持寄存器(常用功能码03)
        :param address: 寄存器起始地址
        :param count: 读取寄存器数量
        :param unit: 从站地址
        :return: 解码后的寄存器值列表
        """
        if not self.connected:
            logger.warning("Modbus未连接,尝试重新连接")
            if not self.connect():
                return None
        
        try:
            # 读取寄存器
            response = self.client.read_holding_registers(
                address=address,
                count=count,
                unit=unit
            )
            
            if response.isError():
                logger.error(f"读取寄存器失败:{response}")
                return None
            
            # 解码寄存器数据(大端序,16位)
            decoder = BinaryPayloadDecoder.fromRegisters(
                response.registers,
                byteorder=Endian.Big,
                wordorder=Endian.Big
            )
            
            # 解析每个寄存器的值
            values = []
            for _ in range(count):
                values.append(decoder.decode_16bit_uint())
            
            logger.info(f"成功读取寄存器[{address}-{address+count-1}],值:{values}")
            return values
        
        except Exception as e:
            logger.error(f"读取寄存器异常:{str(e)}")
            return None

    def close(self):
        """关闭Modbus连接"""
        if self.client:
            self.client.close()
            self.connected = False
            logger.info("Modbus连接已关闭")

# 测试代码
if __name__ == "__main__":
    # 测试RTU模式
    rtu_reader = ModbusReader(
        mode='rtu',
        port='/dev/ttySTM0',
        baudrate=9600,
        parity='N',
        stopbits=1,
        bytesize=8,
        timeout=3
    )
    if rtu_reader.connect():
        rtu_values = rtu_reader.read_holding_registers(address=0, count=4, unit=1)
        print(f"RTU读取结果:{rtu_values}")
        rtu_reader.close()
    
    # 测试TCP模式
    tcp_reader = ModbusReader(
        mode='tcp',
        host='192.168.1.200',
        port=502,
        timeout=3
    )
    if tcp_reader.connect():
        tcp_values = tcp_reader.read_holding_registers(address=0, count=4, unit=1)
        print(f"TCP读取结果:{tcp_values}")
        tcp_reader.close()

3.2 MQTT数据发布模块

创建mqtt_publisher.py文件,实现MQTT客户端的连接与数据发布:

python 复制代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
MQTT数据发布模块
支持QoS 0/1/2,断线重连
"""
import logging
import json
import time
import paho.mqtt.client as mqtt

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('mqtt_publisher.log', encoding='utf-8'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger('MQTTPublisher')

class MQTTPublisher:
    def __init__(self, broker, port=1883, username=None, password=None, client_id=None):
        """
        初始化MQTT客户端
        :param broker: MQTT服务器地址(IP/域名)
        :param port: MQTT端口,默认1883
        :param username: 认证用户名
        :param password: 认证密码
        :param client_id: 客户端ID,为空则自动生成
        """
        self.broker = broker
        self.port = port
        self.username = username
        self.password = password
        self.client_id = client_id if client_id else f"stm32mp1_gateway_{int(time.time())}"
        
        # 创建MQTT客户端
        self.client = mqtt.Client(client_id=self.client_id, clean_session=True)
        
        # 设置认证
        if self.username and self.password:
            self.client.username_pw_set(self.username, self.password)
        
        # 设置回调函数
        self.client.on_connect = self._on_connect
        self.client.on_disconnect = self._on_disconnect
        self.client.on_publish = self._on_publish
        
        # 连接状态
        self.connected = False
        # 重连参数
        self.reconnect_interval = 5  # 重连间隔(秒)
        self.max_reconnect_attempts = 10  # 最大重连次数

    def _on_connect(self, client, userdata, flags, rc):
        """连接回调函数"""
        if rc == 0:
            self.connected = True
            logger.info(f"MQTT连接成功,返回码:{rc}")
        else:
            self.connected = False
            logger.error(f"MQTT连接失败,返回码:{rc}")
            # 返回码说明:
            # 0: 连接成功
            # 1: 协议版本错误
            # 2: 客户端ID无效
            # 3: 服务器不可用
            # 4: 用户名/密码错误
            # 5: 未授权

    def _on_disconnect(self, client, userdata, rc):
        """断开连接回调函数"""
        self.connected = False
        logger.warning(f"MQTT断开连接,返回码:{rc}")
        # 自动重连
        if rc != 0:
            attempt = 0
            while attempt < self.max_reconnect_attempts and not self.connected:
                logger.info(f"尝试重连MQTT服务器,第{attempt+1}次")
                try:
                    self.client.reconnect()
                    time.sleep(self.reconnect_interval)
                    attempt += 1
                except Exception as e:
                    logger.error(f"重连失败:{str(e)}")
                    time.sleep(self.reconnect_interval)
                    attempt += 1

    def _on_publish(self, client, userdata, mid):
        """发布消息回调函数"""
        logger.info(f"MQTT消息发布成功,消息ID:{mid}")

    def connect(self):
        """建立MQTT连接"""
        try:
            # 设置断线重连
            self.client.loop_start()
            # 连接服务器
            self.client.connect(self.broker, self.port, keepalive=60)
            # 等待连接完成(最多5秒)
            timeout = 5
            start_time = time.time()
            while not self.connected and (time.time() - start_time) < timeout:
                time.sleep(0.1)
            return self.connected
        except Exception as e:
            logger.error(f"MQTT连接异常:{str(e)}")
            return False

    def publish(self, topic, data, qos=0, retain=False):
        """
        发布MQTT消息
        :param topic: 发布主题
        :param data: 发布数据(字典/字符串)
        :param qos: QoS等级,0/1/2
        :param retain: 是否保留消息
        :return: 发布结果(成功返回mid,失败返回None)
        """
        if not self.connected:
            logger.warning("MQTT未连接,尝试重新连接")
            if not self.connect():
                return None
        
        try:
            # 数据格式转换(确保为字符串)
            if isinstance(data, dict):
                payload = json.dumps(data, ensure_ascii=False, indent=2)
            else:
                payload = str(data)
            
            # 发布消息
            result = self.client.publish(
                topic=topic,
                payload=payload,
                qos=qos,
                retain=retain
            )
            
            # 等待发布完成
            result.wait_for_publish()
            
            if result.is_published():
                logger.info(f"消息发布到主题[{topic}]成功,QoS:{qos}")
                return result.mid
            else:
                logger.error(f"消息发布到主题[{topic}]失败")
                return None
        
        except Exception as e:
            logger.error(f"发布消息异常:{str(e)}")
            return None

    def close(self):
        """关闭MQTT连接"""
        if self.client:
            self.client.loop_stop()
            self.client.disconnect()
            self.connected = False
            logger.info("MQTT连接已关闭")

# 测试代码
if __name__ == "__main__":
    # 初始化MQTT发布器
    mqtt_pub = MQTTPublisher(
        broker='192.168.1.10',  # 替换为你的MQTT服务器地址
        port=1883,
        username='admin',       # 替换为实际用户名(无则留空)
        password='123456'       # 替换为实际密码(无则留空)
    )
    
    # 连接MQTT服务器
    if mqtt_pub.connect():
        # 构造测试数据
        test_data = {
            "device_id": "sensor_001",
            "timestamp": int(time.time()),
            "modbus_data": {
                "register_0": 256,
                "register_1": 1024,
                "register_2": 512,
                "register_3": 768
            },
            "gateway_id": "stm32mp1_001"
        }
        
        # 发布数据
        mqtt_pub.publish(
            topic="industrial/modbus2mqtt/sensor_data",
            data=test_data,
            qos=1,
            retain=False
        )
        
        # 关闭连接
        time.sleep(2)
        mqtt_pub.close()

3.3 主程序(协议转换整合)

创建modbus2mqtt_gateway.py文件,整合Modbus读取和MQTT发布功能:

python 复制代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Modbus转MQTT边缘网关主程序
支持定时读取、异常处理、配置文件加载
"""
import logging
import time
import json
import os
from modbus_reader import ModbusReader
from mqtt_publisher import MQTTPublisher

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('modbus2mqtt_gateway.log', encoding='utf-8'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger('Modbus2MQTTGateway')

# 配置文件路径
CONFIG_FILE = "gateway_config.json"

# 默认配置
DEFAULT_CONFIG = {
    "modbus": {
        "mode": "rtu",  # rtu/tcp
        "rtu": {
            "port": "/dev/ttySTM0",
            "baudrate": 9600,
            "parity": "N",
            "stopbits": 1,
            "bytesize": 8,
            "timeout": 3
        },
        "tcp": {
            "host": "192.168.1.200",
            "port": 502,
            "timeout": 3
        },
        "read_params": {
            "address": 0,
            "count": 4,
            "unit": 1,
            "interval": 5  # 读取间隔(秒)
        }
    },
    "mqtt": {
        "broker": "192.168.1.10",
        "port": 1883,
        "username": None,
        "password": None,
        "topic": "industrial/modbus2mqtt/sensor_data",
        "qos": 1,
        "retain": False
    },
    "gateway": {
        "id": "stm32mp1_001",
        "device_id": "sensor_001"
    }
}

def load_config():
    """加载配置文件,不存在则创建默认配置"""
    try:
        if os.path.exists(CONFIG_FILE):
            with open(CONFIG_FILE, 'r', encoding='utf-8') as f:
                config = json.load(f)
            logger.info(f"配置文件加载成功:{CONFIG_FILE}")
            return config
        else:
            # 创建默认配置文件
            with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
                json.dump(DEFAULT_CONFIG, f, ensure_ascii=False, indent=2)
            logger.info(f"默认配置文件已创建:{CONFIG_FILE}")
            return DEFAULT_CONFIG
    except Exception as e:
        logger.error(f"配置文件加载失败,使用默认配置:{str(e)}")
        return DEFAULT_CONFIG

def main():
    """主程序入口"""
    # 加载配置
    config = load_config()
    
    # 初始化Modbus读取器
    modbus_config = config['modbus']
    if modbus_config['mode'] == 'rtu':
        modbus_reader = ModbusReader(
            mode='rtu',
            port=modbus_config['rtu']['port'],
            baudrate=modbus_config['rtu']['baudrate'],
            parity=modbus_config['rtu']['parity'],
            stopbits=modbus_config['rtu']['stopbits'],
            bytesize=modbus_config['rtu']['bytesize'],
            timeout=modbus_config['rtu']['timeout']
        )
    else:
        modbus_reader = ModbusReader(
            mode='tcp',
            host=modbus_config['tcp']['host'],
            port=modbus_config['tcp']['port'],
            timeout=modbus_config['tcp']['timeout']
        )
    
    # 初始化MQTT发布器
    mqtt_config = config['mqtt']
    mqtt_publisher = MQTTPublisher(
        broker=mqtt_config['broker'],
        port=mqtt_config['port'],
        username=mqtt_config['username'],
        password=mqtt_config['password']
    )
    
    # 连接MQTT服务器
    if not mqtt_publisher.connect():
        logger.error("MQTT服务器连接失败,程序退出")
        return
    
    # 连接Modbus设备
    if not modbus_reader.connect():
        logger.error("Modbus设备连接失败,程序退出")
        mqtt_publisher.close()
        return
    
    # 读取参数
    read_params = modbus_config['read_params']
    address = read_params['address']
    count = read_params['count']
    unit = read_params['unit']
    interval = read_params['interval']
    
    # 网关信息
    gateway_config = config['gateway']
    gateway_id = gateway_config['id']
    device_id = gateway_config['device_id']
    
    # MQTT发布参数
    mqtt_topic = mqtt_config['topic']
    mqtt_qos = mqtt_config['qos']
    mqtt_retain = mqtt_config['retain']
    
    logger.info("Modbus转MQTT网关启动成功,开始数据采集与转换")
    
    try:
        while True:
            # 读取Modbus数据
            modbus_data = modbus_reader.read_holding_registers(
                address=address,
                count=count,
                unit=unit
            )
            
            if modbus_data is not None and len(modbus_data) > 0:
                # 构造MQTT发布数据
                publish_data = {
                    "gateway_id": gateway_id,
                    "device_id": device_id,
                    "timestamp": int(time.time()),
                    "modbus": {
                        "address": address,
                        "count": count,
                        "unit": unit,
                        "values": modbus_data
                    }
                }
                
                # 发布MQTT消息
                mqtt_publisher.publish(
                    topic=mqtt_topic,
                    data=publish_data,
                    qos=mqtt_qos,
                    retain=mqtt_retain
                )
            
            # 等待下一次读取
            time.sleep(interval)
    
    except KeyboardInterrupt:
        logger.info("用户中断程序,开始关闭资源")
    except Exception as e:
        logger.error(f"程序运行异常:{str(e)}")
    finally:
        # 关闭连接
        modbus_reader.close()
        mqtt_publisher.close()
        logger.info("Modbus转MQTT网关已停止")

if __name__ == "__main__":
    main()

四、配置与运行(零基础操作步骤)

4.1 配置文件修改

  1. 查看生成的gateway_config.json文件:

    bash 复制代码
    cat gateway_config.json
  2. 根据实际环境修改配置:

    • Modbus部分:
      • mode:根据设备类型选择rtutcp
      • RTU模式:修改port(串口设备,如/dev/ttySTM0)、baudrate(波特率)等参数
      • TCP模式:修改host(Modbus TCP设备IP)、port(默认502)
      • interval:设置数据读取间隔(秒)
    • MQTT部分:
      • broker:修改为你的MQTT服务器IP/域名
      • username/password:MQTT服务器认证信息(无则留空)
      • topic:自定义MQTT发布主题
    • Gateway部分:修改gateway_iddevice_id为实际设备ID

4.2 串口权限配置(RTU模式必做)

bash 复制代码
# 将当前用户添加到dialout组(访问串口需要)
sudo usermod -aG dialout $USER
# 重启生效(或重新登录)
sudo reboot
# 验证串口权限
ls -l /dev/ttySTM0

4.3 运行网关程序

bash 复制代码
# 赋予脚本执行权限
chmod +x modbus2mqtt_gateway.py
# 运行程序
python3 modbus2mqtt_gateway.py

4.4 后台运行

bash 复制代码
# 使用nohup后台运行,日志输出到gateway.log
nohup python3 modbus2mqtt_gateway.py > gateway.log 2>&1 &
# 查看运行状态
ps -ef | grep modbus2mqtt_gateway.py
# 停止程序
kill -9 [进程ID]

五、调试与验证

5.1 日志查看

bash 复制代码
# 实时查看Modbus读取日志
tail -f modbus_reader.log
# 实时查看MQTT发布日志
tail -f mqtt_publisher.log
# 实时查看网关主日志
tail -f modbus2mqtt_gateway.log

5.2 MQTT数据验证

使用MQTT.fx或mosquitto_sub工具订阅主题,验证数据是否正常接收:

bash 复制代码
# 安装mosquitto客户端
sudo apt install -y mosquitto-clients
# 订阅MQTT主题
mosquitto_sub -h 192.168.1.10 -t "industrial/modbus2mqtt/sensor_data" -v

5.3 常见问题排查

  1. Modbus连接失败:

    • 检查串口/网口硬件连接
    • 确认Modbus从站地址、波特率、寄存器地址等参数正确
    • 测试命令:minicom -D /dev/ttySTM0 -b 9600(RTU)/ ping 192.168.1.200(TCP)
  2. MQTT发布失败:

    • 检查MQTT服务器地址、端口、认证信息
    • 确认网络连通性:telnet 192.168.1.10 1883
    • 检查MQTT服务器是否开启,防火墙是否放行1883端口
  3. 数据解析异常:

    • 确认寄存器数据类型(16位无符号/有符号、32位浮点等)
    • 修改modbus_reader.py中的解码方式(如decode_16bit_int/decode_32bit_float

六、开机自启配置

创建系统服务文件,实现网关程序开机自启:

bash 复制代码
# 创建服务文件
sudo nano /etc/systemd/system/modbus2mqtt.service

写入以下内容:

ini 复制代码
[Unit]
Description=Modbus to MQTT Gateway Service
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/home/root/modbus2mqtt  # 替换为你的程序目录
ExecStart=/usr/bin/python3 /home/root/modbus2mqtt/modbus2mqtt_gateway.py
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

启用并启动服务:

bash 复制代码
# 重新加载系统服务
sudo systemctl daemon-reload
# 设置开机自启
sudo systemctl enable modbus2mqtt
# 启动服务
sudo systemctl start modbus2mqtt
# 查看服务状态
sudo systemctl status modbus2mqtt

总结

  1. 本教程基于STM32MP1的Linux系统,实现了Modbus RTU/TCP到MQTT的协议转换,包含完整的代码实现和零基础操作步骤,可直接落地部署。
  2. 核心流程为:Modbus设备数据读取 → 协议解析与数据校验 → JSON格式封装 → MQTT协议发布 → 物联网平台接收,全流程包含异常处理和自动重连机制。
  3. 关键配置项包括Modbus连接参数(串口/网口)、MQTT服务器信息、数据读取间隔等,可通过配置文件灵活调整,支持开机自启和后台运行。
相关推荐
cyber_两只龙宝2 小时前
Nginx--企业高性能web服务器高级配置详解
linux·运维·nginx·云原生
i建模4 小时前
Omarchy设置防火墙
linux·运维
Max_uuc4 小时前
【硬件心法】打破软硬边界:从原理图剖析探秘“微安级”精密电流采样的底层架构
单片机·嵌入式硬件
S-码农4 小时前
Linux ——条件变量
linux·开发语言
爱写代码的liding4 小时前
linux安装软件过程中报找不到某些动态链接.so文件
linux
青衫码上行5 小时前
【项目部署】Spring Boot项目部署的四种方式
java·linux·服务器·spring boot·后端·docker·腾讯云
礼拜天没时间.6 小时前
JumpServer堡垒机部署与实战:从0到1搭建统一运维入口
linux·运维·架构·堡垒机·jumpserver·sre
林姜泽樾6 小时前
linux入门第四章,cd指令和相对、绝对路径
linux·运维·服务器
jjjxxxhhh1236 小时前
[Google Test]- Google Test Ubuntu 完整验证指南
linux·数据库·ubuntu