Python串口被占用或权限不足怎么解决

巷口听风
巷口听风
发布时间:2026-10-23| 6人浏览过
原创

在使用 Python 进行串口通信(通常基于 pyserial 库)时,程序无法正常打开串口设备,绝大多数情况下都归因于两类问题:端口已被其他进程独占(串口被占用)或操作系统拒绝了当前用户的设备读写请求(权限不足)。解决这一问题的核心逻辑在于先依据报错特征区分具体类型,随后通过操作系统工具释放占用进程,或通过用户组及策略配置赋予程序必要的设备访问权。

一、现象识别:区分串口占用与权限不足

在 Python 运行 serial.Serial(port, baudrate) 时,底层依赖操作系统提供的设备文件或句柄。由于串口属于独占性字符设备,操作系统不允许两个程序同时打开同一个通信端口。当调用失败时,pySerial 会抛出 serial.serialutil.SerialException,但具体异常提示在不同系统下有所侧重:

  • 串口被占用的典型表现:在 Linux 或 macOS 系统中,通常明确抛出 [Errno 16] Device or resource busy;在 Windows 系统中,则常提示 could not open port 'COMx': PermissionError(13, '拒绝访问。', None, 5)。需要特别注意:Windows 系统下端口被其他软件占用时,底层同样会返回“拒绝访问”(错误码 5),常被初学者误判为系统权限问题。
  • 权限不足的典型表现:主要集中在 Linux 与 macOS 环境,错误明确为 [Errno 13] Permission denied: '/dev/ttyUSB0'。这表明端口并未被其他程序锁死,但当前登录用户不在该设备节点的授权用户组列表中。
Python串口被占用或权限不足怎么解决
图 1:Python 串口异常分类与判定逻辑示意图

二、串口被占用的排查与解决步骤

当端口处于忙碌状态时,核心任务是找到持有该串口句柄的具体进程并将其终止。不同操作系统的排查工具和处理流程如下:

1. Linux 与 macOS 系统下的排查流程

在类 Unix 系统中,串口以设备文件的形式存在于 /dev/ 目录下(常见如 /dev/ttyUSB0、/dev/ttyACM0、macOS 下的 /dev/cu.usbserial-*)。可以使用 lsof 或 fuser 命令定位进程:

步骤一:定位占用进程的 PID

# 使用 lsof 列出打开该设备文件的进程
lsof /dev/ttyUSB0

# 或者使用 fuser 检查(推荐带详细信息参数)
fuser -v /dev/ttyUSB0

示例输出中会显示进程名(如 python3、minicom 或 screen)以及进程号(PID)。如果命令无输出但依然报错,尝试加上 sudo 运行以查看其他用户启动的守护进程。

步骤二:终止占用进程

# 平稳终止进程(将 1234 替换为实际查出的 PID)
kill 1234

# 若进程无响应,使用强制信号
kill -9 1234

# 也可以直接用 fuser 一键释放占用
sudo fuser -k /dev/ttyUSB0

注意:警惕 Linux 下的 ModemManager 干扰

在 Ubuntu 等桌面发行版中,系统自带的 ModemManager 服务会在插入 USB 转串口芯片(如 CH340、CP2102、FT232)时自动尝试将其识别为调制解调器,占用串口约 10 至 30 秒进行探测。若日常无需移动宽带模块,建议将其禁用或过滤:

# 临时停止服务
sudo systemctl stop ModemManager

# 永久禁用服务
sudo systemctl disable ModemManager

2. Windows 系统下的排查流程

在 Windows 环境下,串口被占用通常是因为前台运行了串口调试助手(如 SSCOM、XCOM)、其他 IDE 的串口监视器,或者是上一次调试中断后残留在后台的 python.exe 进程。

  1. 关闭可见窗口:检查任务栏与托盘区,关闭可能打开该 COM 口的所有软件。
  2. 结束后台 Python 进程:打开任务管理器(快捷键 Ctrl + Shift + Esc),切换到“详细信息”页,查找名为 python.exe 的进程。如果在集成开发环境(如 VS Code、PyCharm)中曾强制终止过运行,可能产生孤立僵尸进程,直接右键结束任务。
  3. 使用资源监视器查找句柄:
    • 按 Win + R 运行 resmon.exe 打开资源监视器。
    • 切换到“CPU”标签页,展开“关联的句柄”。
    • 在搜索框中输入对应的端口标识(例如输入 \Device\Serial 或直接搜索端口名称)。
    • 搜索到的程序即为占用源,选中后右键“结束进程”。
Python串口被占用或权限不足怎么解决
图 2:串口被占用的四步排查与释放流程图

三、解决串口权限不足的配置与授权方法

在 Linux 发行版中,USB 串口适配器插上后会在 /dev/ 自动生成设备节点。查看该节点的权限:

# 查看串口文件所有者及权限
ls -l /dev/ttyUSB0

典型输出如下:

crw-rw---- 1 root dialout 188, 0 10月 20 20:30 /dev/ttyUSB0

该权限表示仅有拥有者 root 和所属用户组 dialout(部分系统如 Arch/Fedora 可能是 uucp)具备读写权限(rw-),其他用户无任何权限。普通用户运行 Python 自然会触发 Permission denied。

1. 规范推荐:将当前用户加入串口所属用户组

最标准且安全的解决方案是将当前执行 Python 脚本的用户添加到对应的设备管理组中,避免依赖超级用户权限运行业务代码。

Ubuntu / Debian / Mint 系统(默认组为 dialout):

# 将当前登录用户加入 dialout 组
sudo usermod -aG dialout $USER

Arch Linux / Manjaro / Fedora 系统(默认组通常为 uucp):

# 将当前用户加入 uucp 组
sudo usermod -aG uucp $USER
核心提醒:生效必须重新登录会话

运行 usermod 更改用户附加组后,当前的 shell 会话并不会自动继承新组信息。必须完全注销当前桌面会话并重新登录,或者重启电脑。在终端中可通过输入 groups 或 id 查看返回列表中是否已包含 dialout。如果临时需要测试,可在终端运行 newgrp dialout 刷新当前终端的环境。

2. 进阶方案:编写 udev 规则指定设备权限

若希望特定 USB 串口设备插入时自动对所有用户开放权限(如 0666),或根据硬件序列号固定设备别名,可以通过配置 udev 规则实现:

# 1. 查找设备的 Vendor ID (idVendor) 与 Product ID (idProduct)
lsusb
# 假设输出中包含:Bus 001 Device 004: ID 1a86:7523 QinHeng Electronics CH340 serial converter

# 2. 创建自定义 udev 规则文件
sudo nano /etc/udev/rules.d/99-serial.rules

# 3. 写入规则内容(填入对应的 idVendor 和 idProduct)
SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE="0666"

# 4. 重载 udev 规则并使其生效
sudo udevadm control --reload-rules
sudo udevadm trigger

重新插拔 USB 转串口硬件后,该硬件创建的 /dev/tty* 节点权限将直接变更为 crw-rw-rw-,任意普通用户均可正常访问。

Python串口被占用或权限不足怎么解决
图 3:Linux 串口权限模型与用户组授权架构图

四、Python 代码层面的防范与异常优雅处理

在许多情况下,串口被占用并非由于第三方软件,而是因为 Python 脚本在运行过程中抛出未捕获异常退出,而底层的串口句柄未被显式关闭,导致操作系统未能及时释放文件锁。规范的代码结构可杜绝此类自身原因导致的端口挂死。

1. 使用上下文管理器自动释放句柄

pyserial 的 Serial 对象原生支持 Python 上下文管理器协议(with 语句)。当退出代码块时,无论正常完成还是遭遇不可控异常,解释器都会自动调用 close() 释放句柄:

import serial
import serial.tools.list_ports

def read_serial_data(port_name, baudrate=115200):
    try:
        # 使用 with 上下文管理器,离开代码块自动安全关闭
        with serial.Serial(port_name, baudrate, timeout=1) as ser:
            print(f"成功打开串口: {ser.name}")
            while True:
                line = ser.readline()
                if line:
                    print("收到数据:", line.decode('utf-8', errors='replace').strip())
    except serial.SerialException as e:
        print(f"串口通信异常: {e}")
    except KeyboardInterrupt:
        print("用户中断,句柄已由上下文管理器安全释放")

2. 编写健壮的容错重试与端口检测逻辑

在工业或长期后台运行脚本中,可以加入端口枚举与错误检测,避免直接因单次失败而崩溃:

import time
import serial
import serial.tools.list_ports

def safe_open_port(target_port, baudrate=9600, max_retries=3):
    """检测可用端口并尝试安全连接"""
    available_ports = [p.device for p in serial.tools.list_ports.comports()]
    if target_port not in available_ports:
        print(f"目标端口 {target_port} 未就绪,当前可用端口列表: {available_ports}")
        return None

    for attempt in range(1, max_retries + 1):
        try:
            ser = serial.Serial(target_port, baudrate, timeout=2)
            return ser
        except serial.SerialException as err:
            err_msg = str(err)
            if "PermissionError" in err_msg or "拒绝访问" in err_msg or "busy" in err_msg:
                print(f"[尝试 {attempt}/{max_retries}] 端口 {target_port} 忙碌或被占用,等待释放...")
                time.sleep(2)
            else:
                print(f"不可恢复的串口异常: {err}")
                break
    return None

五、排查要点与操作对照总结

当遇到串口错误时,读者可以依照下表的排查路径快速完成定位与处置:

操作系统 典型报错特征 根本原因 首选解决方式
Windows could not open port: PermissionError(13, '拒绝访问。') 端口被串口调试助手、后台 Python 或其他上位机软件独占 任务管理器结束残留 python.exe,关闭串口助手,或在资源监视器搜索句柄
Linux [Errno 13] Permission denied: '/dev/ttyUSB0' 当前用户缺少对设备文件的读写权限 执行 sudo usermod -aG dialout $USER 并注销重新登录
Linux [Errno 16] Device or resource busy 后台其他进程占用、或 ModemManager 正在探测串口 使用 fuser -k /dev/ttyUSB0 释放,停止或禁用 ModemManager 服务
跨平台 多次调试后偶发性被占用 脚本异常退出导致 close() 未执行 使用 with serial.Serial(...) as ser: 上下文管理器管理连接生命周期
Python串口被占用或权限不足怎么解决
图 4:串口问题解决清单与代码最佳实践全景图
相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。