伪终端主控读取刚写入的数据
我正在做一个项目,这个项目需要把“虚拟设备”(用Python进程表示)和真实设备(也用串口连接)连接起来。我使用伪终端来连接多个(超过两个)串口通信进程(模拟串行设备),但是遇到了一些问题。
我有一个Python进程,它生成伪终端,并把伪终端的从端(slave)链接到一个文件(这样进程就可以通过这个文件创建一个pyserial对象),而主端(master)则由我的伪终端生成进程来管理和读取。当一个主端收到数据时,这些数据会被记录下来,然后写入到其他的主端。如果监听的进程一直在,这种方法是有效的。
问题在于,当虚拟设备崩溃或者根本没有启动时(这在这个项目中是一个合理的使用场景)。在我的系统上,如果数据写入到伪终端的主端,而从端没有任何东西在监听,那么在主端调用读取(read)时,会返回刚刚写入的数据!这意味着设备会收到重复的数据——这可不好!
举个例子:
>>master, slave = pty.openpty()
>>os.write(master,"Hello!")
6
>>os.read(master,6)
'Hello!'
我希望调用read()时能够阻塞,直到从端发送数据。实际上,这正是从设备的行为——它可以写入,然后os.read(slave,1)会阻塞,直到主端写入数据。
我的“虚拟设备”需要能够传递一个文件名来打开串口对象;我尝试链接主端,但这导致我的虚拟设备打开了/dev/ptmx,这样会创建一对新的伪终端,而不是链接到已经存在的从端!
有没有办法改变主端的行为?或者仅仅是获取一个与从设备对应的主端文件名(而不是/dev/ptmx)?
提前谢谢你!
2 个回答
如果有人看到这个问题,而jszakmeister的回答没有解决你的问题,这里有我成功的做法。
openpty
这个函数似乎会在一种叫做“规范模式”的状态下创建伪终端,并且会开启回显功能。这可能和你预想的有点不一样。你可以通过使用tty.setraw
这个函数来改变模式,下面是一个简单的使用openpty的回显服务器的例子:
master, slave = os.openpty()
tty.setraw(master, termios.TCSANOW)
print("Connect to:", os.ttyname(slave))
while True:
try:
data = os.read(master, 10000)
except OSError:
break
if not data:
break
os.write(master, data)
我很确定这是因为默认情况下是开启回显的。借用一下Python termios 文档中的内容,你可以这样做:
master, slave = os.openpty() # It's preferred to use os.openpty()
old_settings = termios.tcgetattr(master)
new_settings = termios.tcgetattr(master) # Does this to avoid modifying a reference that also modifies old_settings
new_settings[3] = new_settings[3] & ~termios.ECHO
termios.tcsetattr(master, termios.TCSADRAIN, new_settings)
你可以使用以下代码来恢复之前的设置:
termios.tcsetattr(master, termios.TCSADRAIN, old_settings)