我正在创建一个像这样的假串行设备:
socat -d -d pty,raw,echo=0 pty,raw,echo=0
这每次都会创建具有新编号的设备。让我们打电话/dev/pty/6
给他们/dev/pty/7
为了模拟我的测试机器上没有的硬件设备,我以/dev/pty/6
每秒二十行的速度写入。
与此类似(在我的实际项目中,我正在使用 python 编写,但这显示了相同的问题)
while true
do
date > /dev/pts/6
sleep 0.05
done
我注意到,如果我让它cat
/dev/pty/7
运行几秒钟,它就会从我上次停下的地方开始,而不是从我写的下一行开始。
所以如果我timeout 5 cat -n /dev/pty/7
一遍又一遍地看,中间没有休息,我总是会得到大约 100 行。但是,如果我让“生产者”脚本运行五分钟,然后运行timeout 5 cat -n /dev/pty/7
,我会得到数千行 - 我猜是自上次阅读以来编写的所有行。
我试图模拟的实际硬件的行为并非如此。
timeout 5 cat -n /dev/ttyUSB0
总是给我大约一百行。它只是扔掉了没有人读的行。
如何更好地模拟硬件设备的这方面?制作者脚本是否需要检查是否有人正在读取且仅写入?或者我必须给 socat 命令提供一个选项吗?
我认为当我使用 python 执行此操作时,它正在写入的缓冲区已满,并且生产者程序陷入等待写入空间的状态,但我无法在本例中证明这一点。
答案1
使用此方法的问题socat
是 pty 有很大的缓冲区。由于您使用的是 Python,因此您可以尝试自己模拟一些东西。例如,
#!/usr/bin/python3
# https://unix.stackexchange.com/a/735081/119298
# some termios code from:
# https://github.com/pyserial/pyserial/blob/master/serial/serialposix.py
import os, time, struct, fcntl, termios
class pseudotty:
TIOCM_zero_str = struct.pack('I', 0)
def __init__(self, name, mode):
master, slave = os.openpty()
sname = os.readlink(f"/proc/self/fd/{slave}") # "/dev/pts/6"
os.unlink(name)
os.symlink(sname, name)
self.mfd = master
self.sfd = slave
self.file = os.fdopen(master, mode)
def waiting(self):
result = fcntl.ioctl(self.sfd, termios.FIONREAD, self.TIOCM_zero_str)
return struct.unpack('I', result)[0]
datain = pseudotty("input", "r")
dataout = pseudotty("output", "w")
while True:
d = datain.file.readline()
wait = dataout.waiting()
if wait<200:
dataout.file.write(d)
这将创建并打开两个 pty,在当前工作目录中具有指向每个从站的符号链接,input
并且output
.因此,您可以引导循环使用date >input
, 和cat
to
cat output
。
该程序永远循环:它从输入 pty 读取一行,测试输出 pty 中当前等待的字符数,如果少于 200 个字符,则将该行写入输出。如果超过 200 个字符,则输入将被丢弃。
这可以让您对两个 pty 之间缓冲的数据量进行一些控制。当然,您可以将 替换readline()
为read(1)
,并将 200 限制替换为 15;这可以模拟许多具有有限 fifo 的串行设备。