我知道还有其他问题与我的很相似,但是他们都没有解决我遇到的问题。
我想使用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
子例外)。
与其他解决方案相比,这有两个优点:
所以,你的函数看起来像这样:
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