Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用Python2.7(可能还有pyserial)在Linux中检查串行端口是否已经打开(由另一个进程打开)?_Python_Linux_Python 2.7_Pyserial - Fatal编程技术网

如何使用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()
    并重新打开串行端口。旧线程,但可能仍有人潜伏在附近:)