如何使用Python2.7(可能还有pyserial)在Linux中检查串行端口是否已经打开(由另一个进程打开)?
我知道还有一些问题与我的问题非常相似,但没有一个能解决我的问题 我想使用如何使用Python2.7(可能还有pyserial)在Linux中检查串行端口是否已经打开(由另一个进程打开)?,python,linux,python-2.7,pyserial,Python,Linux,Python 2.7,Pyserial,我知道还有一些问题与我的问题非常相似,但没有一个能解决我的问题 我想使用pyserial访问串行端口(/dev/tty…),但前提是其他进程尚未打开它 当运行一次时,下面的代码段返回我的Ubuntu 12.04机器上的四个可用端口。如果我第二次运行它,我希望没有可用的端口。遗憾的是,返回了相同的端口列表。似乎pyserial无法识别另一个进程已打开该端口 我希望抛出一个SerialException,或者isOpen()方法返回False,但是pyserial会愉快地打开多次 import se
pyserial
访问串行端口(/dev/tty…
),但前提是其他进程尚未打开它
当运行一次时,下面的代码段返回我的Ubuntu 12.04机器上的四个可用端口。如果我第二次运行它,我希望没有可用的端口。遗憾的是,返回了相同的端口列表。似乎pyserial
无法识别另一个进程已打开该端口
我希望抛出一个SerialException
,或者isOpen()
方法返回False,但是pyserial
会愉快地打开多次
import serial
from serial import tools
from serial.tools import list_ports
def available_ttys():
for tty in serial.tools.list_ports.comports():
try:
port = serial.Serial(port=tty[0])
if port.isOpen():
yield port
except serial.SerialException as ex:
print 'Port {0} is unavailable: {1}'.format(tty, ex)
def main():
ttys = []
for tty in available_ttys():
ttys.append(tty)
print tty
input('waiting ...')
if __name__ == '__main__':
main()
import fcntl, serial
s = serial.Serial(0)
fcntl.flock(s.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
无论并行运行多少次,这都是输出:
Port ('/dev/ttyS31', 'ttyS31', 'n/a') is unavailable: Could not configure port: (5, 'Input/output error')
...
Port ('/dev/ttyS0', 'ttyS0', 'n/a') is unavailable: Could not configure port: (5, 'Input/output error')
Serial<id=0x7fca9d9f1c90, open=True>(port='/dev/ttyUSB1', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
Serial<id=0x7fca9d9f1cd0, open=True>(port='/dev/ttyACM2', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
Serial<id=0x7fca9d9f1e50, open=True>(port='/dev/ttyACM1', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
Serial<id=0x7fca9d9f1ed0, open=True>(port='/dev/ttyACM0', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
waiting ...
端口('/dev/ttyS31','ttyS31','n/a')不可用:无法配置端口:(5,'输入/输出错误')
...
端口('/dev/ttyS0','ttyS0','n/a')不可用:无法配置端口:(5,'输入/输出错误')
串行(端口='/dev/ttyUSB1',波特率=9600,字节大小=8,奇偶校验=N',停止位=1,超时=None,xonxoff=False,rtscts=False,dsrdtr=False)
串行(端口='/dev/ttyACM2',波特率=9600,字节大小=8,奇偶校验=N',停止位=1,超时=None,xonxoff=False,rtscts=False,dsrdtr=False)
串行(端口='/dev/ttyACM1',波特率=9600,字节大小=8,奇偶校验=N',停止位=1,超时=None,xonxoff=False,rtscts=False,dsrdtr=False)
串行(端口='/dev/ttyACM0',波特率=9600,字节大小=8,奇偶校验=N',停止位=1,超时=None,xonxoff=False,rtscts=False,dsrdtr=False)
等待。。。
Linux中没有任何东西可以阻止多个进程打开同一个串行端口。因此,pyserial库能够做到这一点。然而,有一个标准的ish公约已在其他地方得到充分的记录:
一般过程要求您打开设备,然后在/tmp
或/var/lock
目录中创建包含PID的文本文件。第二个脚本将搜索此文件的存在,并拒绝打开其存在的端口
有关更多信息,请参阅:,正如@VooDooNOFX所说,在阻止其他进程打开同一端口(设备)方面没有技术限制。但是,在Linux上,您可以锁定该文件,以防止应用程序多次使用同一端口
import serial
from serial import tools
from serial.tools import list_ports
def available_ttys():
for tty in serial.tools.list_ports.comports():
try:
port = serial.Serial(port=tty[0])
if port.isOpen():
yield port
except serial.SerialException as ex:
print 'Port {0} is unavailable: {1}'.format(tty, ex)
def main():
ttys = []
for tty in available_ttys():
ttys.append(tty)
print tty
input('waiting ...')
if __name__ == '__main__':
main()
import fcntl, serial
s = serial.Serial(0)
fcntl.flock(s.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
在这种情况下,应用程序将尝试在串行端口上获取独占锁(lock\u EX
)。多亏了LOCK\u NB
,如果任何其他进程已经锁定了串行端口,则调用将立即失败-通过引发IOError
(或Python 3.3中的BlockingIOError
子异常)
与其他解决方案相比,这有两个优点:
因此,您的函数如下所示:
def available_ttys():
for tty in serial.tools.list_ports.comports():
try:
port = serial.Serial(port=tty[0])
if port.isOpen():
try:
fcntl.flock(port.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
print 'Port {0} is busy'.format(tty)
else:
yield port
except serial.SerialException as ex:
print 'Port {0} is unavailable: {1}'.format(tty, ex)
感谢您提供有关标准ish公约的信息。我会记住的。
fcntl exclusive
似乎更容易实现,所以我将尝试一下。这就是我最终实现的。到目前为止,它工作得很好。我尝试了fcntl解决方案,但它仅在其他进程也使用相同的fcntl锁时保护您。如果另一个进程打开串行端口时没有发出群集调用,那么当您尝试时,即使串行端口已经打开,您的群集也会成功。我有一个RPi从Arduino读取串行数据。这个答案帮助我防止在同一端口中打开另一个进程,但是新进程会破坏原来的进程,因此我会得到损坏的数据。我对这段代码的补充是检测数据何时损坏(JSON vs垃圾),然后关闭ser.close()
并重新打开串行端口。旧线程,但可能仍有人潜伏在附近:)