Linux实现虚拟串口通信-socat

在Linux开发中,我们常需要调试串口通信程序,但有时缺少真实的串口硬件(如USB转串口模块、单片机)。此时,通过软件模拟虚拟串口是高效的解决方案------借助Linux自带的伪终端(Pseudoterminal,

PTY)机制,可创建一对"相互连接"的虚拟串口,让两个程序像操作真实串口一样进行数据交互。本文将详细讲解如何用 socat

工具快速创建虚拟串口,并通过实际示例验证两个程序的通信效果。

一、核心原理:虚拟串口的本质是"伪终端对"

Linux中的虚拟串口并非真实的硬件接口,而是基于"伪终端对"实现的逻辑通道。一个伪终端对包含两个端点:主设备(master)从设备(slave),数据会在两个端点间双向同步传输------从主设备发送的数据会被从设备接收,反之亦然。

我们将这两个端点模拟为"串口设备文件"(如 /dev/ttyS0、/dev/ttyS1),让两个程序分别绑定这两个设备文件,即可实现"程序A→虚拟串口→程序B"的通信链路,完全模拟真实串口的交互逻辑。

二、准备工具:安装socat

socat 是Linux下功能强大的"数据转发工具",支持多种协议和设备的连接,其中就包括伪终端对的创建,是模拟虚拟串口的首选工具。

安装命令:

  1. Debian/Ubuntu :
    sudo apt update && sudo apt install socat -y

  2. CentOS/Fedora :
    sudo dnf install socat -y

  3. 验证安装:
    socat -V

    若输出版本信息(如 socat 1.7.4.4),说明安装成功。

三、步骤1:创建虚拟串口对

通过 socat 命令可直接创建一对相互绑定的虚拟串口,命令格式如下:

bash 复制代码
socat -d -d pty,raw,echo=0,link=/dev/ttyV0 pty,raw,echo=0,link=/dev/ttyV1

命令参数解释:

  • -d -d:输出调试信息(两次 -d 表示详细程度,可省略,便于排查问题);

  • pty:指定创建伪终端设备;

  • raw:设置串口为"原始模式",禁用缓冲区和特殊字符处理(模拟真实串口的无缓冲传输);

  • echo=0:关闭回显功能(避免发送的数据被自身回显,干扰通信);

  • link=/dev/ttyV0:为伪终端设备创建软链接(简化设备名,原伪终端名较长,如 /dev/pts/10),ttyV0ttyV1是自定义的虚拟串口名,可修改(建议用 ttyV 前缀,避免与真实串口 ttyS 冲突)。

执行命令后,终端会输出类似以下的调试信息,说明虚拟串口对创建成功:

text 复制代码
2026/01/14 15:30:00 socat[12345] N PTY is /dev/pts/10
2026/01/14 15:30:00 socat[12345] N PTY is /dev/pts/11
2026/01/14 15:30:00 socat[12345] N starting data transfer loop with FDs [5,5] and [7,7]

此时,/dev/ttyV0 和 /dev/ttyV1 就是一对相互通信的虚拟串口,且软链接已自动创建(可通过 ls -l /dev/ttyV* 查看链接关系)。

⚠️ 注意:创建虚拟串口的终端窗口需保持打开状态(socat 进程运行中),若关闭窗口,虚拟串口会自动消失。

四、步骤2:验证虚拟串口通信(基础测试)

我们先用两个终端窗口模拟"两个程序",通过 catecho 命令测试虚拟串口的双向通信功能。

测试1:单向通信(终端1→终端2)

  1. 打开 终端1 (接收端):绑定 /dev/ttyV0,监听数据:
    cat /dev/ttyV0

  2. 打开 终端2 (发送端):绑定 /dev/ttyV1,发送数据:
    echo "Hello, Virtual Serial Port!" > /dev/ttyV1

  3. 观察结果:终端1会立即显示终端2发送的字符串,说明单向通信正常。

测试2:双向通信(终端1与终端2互发)

  1. 终端1(绑定 /dev/ttyV0):用 read 命令接收数据,同时可发送数据:
    while read -r line; do echo "终端1收到:$line"; done < /dev/ttyV0

  2. 终端2(绑定 /dev/ttyV1):同样用循环接收并发送数据:
    while read -r line; do echo "终端2收到:$line"; done < /dev/ttyV1

  3. 测试互发:

  • 在终端1输入 echo "Hi from V0" > /dev/ttyV0,终端2会显示"终端2收到:Hi from V0";
  • 在终端2输入 echo "Hi from V1" > /dev/ttyV1,终端1会显示"终端1收到:Hi from V1"。

五、步骤3:两个程序通过虚拟串口通信(实战示例)

下面用 Python 编写两个简单的串口程序(发送端+接收端),模拟真实应用场景下的程序间通信。

前提:安装Python串口库

两个程序需用到 pyserial 库,安装命令:
pip install pyserial

程序1:虚拟串口发送端(send.py,绑定 /dev/ttyV1)

python 复制代码
import serial
import time

# 配置虚拟串口参数(波特率、超时时间等,需与接收端一致)
ser = serial.Serial(
    port='/dev/ttyV1',    # 绑定虚拟串口V1
    baudrate=9600,        # 波特率(虚拟串口可任意设置,真实串口需匹配)
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    timeout=1             # 读取超时时间(秒)
)

# 循环发送数据
try:
    print("发送端启动,开始发送数据...")
    count = 0
    while True:
        data = f"Test data {count}: Hello Virtual Serial!\n"
        ser.write(data.encode('utf-8'))  # 编码为字节流发送
        print(f"已发送:{data.strip()}")
        count += 1
        time.sleep(2)  # 每2秒发送一次
except KeyboardInterrupt:
    print("\n发送端退出")
    ser.close()  # 关闭串口

程序2:虚拟串口接收端(recv.py,绑定 /dev/ttyV0)

python 复制代码
import serial

# 配置虚拟串口参数(与发送端完全一致)
ser = serial.Serial(
    port='/dev/ttyV0',
    baudrate=9600,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    timeout=1
)

# 循环接收数据
try:
    print("接收端启动,等待数据...")
    while True:
        if ser.in_waiting > 0:  # 检测是否有数据可读
            data = ser.readline().decode('utf-8').strip()  # 读取一行数据并解码
            print(f"接收端收到:{data}")
except KeyboardInterrupt:
    print("\n接收端退出")
    ser.close()

运行程序并验证

  1. 确保之前创建虚拟串口的终端窗口仍打开(socat 进程运行中);

  2. 打开 终端3 ,运行接收端程序:
    python recv.py

  3. 打开 终端4 ,运行发送端程序:
    python send.py

  4. 观察结果:接收端会每隔2秒收到发送端发送的测试数据,类似以下输出:

    接收端启动,等待数据...

    接收端收到:Test data 0: Hello Virtual Serial!

    接收端收到:Test data 1: Hello Virtual Serial!

    接收端收到:Test data 2: Hello Virtual Serial!

六、常见问题与注意事项

1. 权限问题:Permission denied

现象:运行程序或访问 /dev/ttyV0 时提示"权限拒绝"。

解决:将当前用户加入 dialout 用户组(Linux串口设备默认属于该组),命令:
sudo usermod -aG dialout $USER

执行后注销当前用户并重新登录,权限即可生效。

2. 虚拟串口消失

原因:创建虚拟串口的 socat 进程被终止(如关闭终端窗口)。

解决:重新执行 socat 创建命令,确保该终端窗口持续打开。

3. 程序通信失败

排查方向:

  • 两个程序的串口参数(波特率、数据位、停止位、校验位)是否完全一致;
  • 程序绑定的虚拟串口是否正确(需分别绑定 ttyV0 和 ttyV1,不可重复);
  • 虚拟串口是否正常创建(用 ls -l /dev/ttyV* 检查软链接)。

4. 自定义虚拟串口名

若不想用 ttyV0/ttyV1,可修改 socat 命令中的 link 参数,如 link=/dev/ttyS10link=/dev/mySerial0,但需避免与系统真实串口名冲突(真实串口通常为 ttyS0-ttyS3)。

相关推荐
cui__OaO2 小时前
Linux内核--基于正点原子IMX6ULL开发板的内核移植
linux·嵌入式
济6172 小时前
linux 系统移植(第五期)--Uboot移植(4)--在U-Boot 中添加自己的开发板(4) -其他需要修改的地方-- Ubuntu20.04
linux·运维·服务器
老顾聊技术2 小时前
“Anthropic 最新发布的 AI Skills:赋能任务自动化与跨领域应用“
运维·人工智能·自动化
令狐少侠20112 小时前
Linux 系统部署夜莺 nightingale 监控公司的watchdog
linux·运维·服务器
信工 18022 小时前
RK3588系统烧录后扩容
linux·rk3588
Jay Chou why did3 小时前
程序启动地址0x80000000
linux
kkce3 小时前
域名CDN检测意义
服务器·前端·网络
百度Geek说3 小时前
百度流式计算开发平台的降本增效之路
运维·云原生
e***98573 小时前
MobaXterm全能运维实战指南
运维