如何检查串口是否已经打开(通过另一个进程)在Linux中,使用Python 2.7(可能pyserial)?

我知道还有其他问题与我的很相似,但是他们都没有解决我遇到的问题。

我想使用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() 

这是输出,不pipe我平行运行多less次:

 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 ... 

正如@VooDooNOFX所说,防止其他进程打开同一个端口(设备)没有技术限制。 但是,在Linux上,您可以锁定文件以防止应用程序多次使用相同的端口。

 import fcntl, serial s = serial.Serial(0) fcntl.flock(s.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB) 

在这种情况下,您的应用程序将尝试获取串行端口上的独占锁( LOCK_EX )。 感谢LOCK_NB ,如果有任何其他进程已经锁定串口,调用将立即失败 – 通过提高IOError (或Python 3.3中的BlockingIOError子例外)。

与其他解决方案相比,这有两个优点:

  1. 您不会引入任何非标准文件,而是使用系统提供的方法,从而带来更好的互操作性,
  2. 当你的进程退出时,锁立即被释放,所以你不必担心陈旧的锁。

所以,你的函数看起来像这样:

 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) 

Linux中没有任何东西可以阻止多个进程打开相同的串口。 因此,为什么pyserial库能够做到这一点。 然而,有一个标准的公约,其他地方已经有很好的文档: https : //superuser.com/questions/488908/sharing-a-serial-port-between-two-processes

通用过程要求您打开设备,然后在包含您的PID的/tmp/var/lock目录中创建一个文本文件。 第二个脚本会搜索这个文件的存在,并拒绝打开它存在的端口。

有关更多信息,请参阅: http : //www.tldp.org/HOWTO/Serial-HOWTO-13.html