python - 完成当前迭代后,如何结束带有套接字操作的无限循环?

标签 python sockets interrupt

我有一个无限循环,其中有些操作在退出循环之前必须完全执行。也就是说,我正在使用套接字库连接到外部设备,并且我需要等待读取指令完成才能中断循环。

我尝试使用信号处理程序(如 this question )在检测到键盘中断时引发标志。

当前代码:

import videosensor
import signal

def signal_handler(signal, frame):
    """Raises a flag when a keyboard interrupt is raised."""
    global interrupted
    interrupted = True

if __name__ == '__main__':
    camera = videosensor.VideoSensor(filename)
    interrupted = False
    signal.signal(signal.SIGINT, signal_handler)

    while not interrupted:
        location = camera.get_register()
        #...
        #More irrelevant stuff is executed.
        #...
        time.sleep(0.01)

    #This code has to be executed after exiting while loop
    camera_shutdown(camera)

在前面的代码中,videosensor.VideoSensor是一个包含用于从外部设备获取数据的套接字操作的类。主例程中使用的 get_register() 方法如下:

def get_register(self):
    """Read the content of the specified register.
    """
    #Do some stuff
    value = socket.recv(2048)
    return value

问题:

我希望 while 循环持续执行,直到用户按下按键或使用键盘中断,但在当前迭代完成之后。相反,使用以前的解决方案并不能按预期工作,因为它会中断正在进行的指令,并且如果它正在读取套接字,则会引发错误:

/home/.../client.pyc in read_register(self, regkey)

    164         reg = self._REGISTERS[regkey]
    165         self.send('r,{}\n'.format(reg))
--> 166         value = socket.recv(2048)
    167         #Convert the string input into a valid value e.g. list or int
    168         formatted_result = ast.literal_eval(value)

error: [Errno 4] Interrupted system

<小时/>

编辑:从下面的答案来看,似乎没有办法使用键盘中断并避免套接字读取功能被中止。尽管有捕获错误的解决方案,但它们无法避免读取取消。

不过,我有兴趣找到一种获取用户输入的方法,例如特定的按键按下,会引发标志,该标志将在循环结束时进行检查,而不会中断主例程的执行,直到进行此检查。

编辑2:使用的操作系统是Linux发行版Ubuntu 14.04

最佳答案

经过快速搜索,我发现 this solution for your issue

基本上,您无能为力:当您向进程发送 SIGINT 时,套接字也会返回 SIGINT。那么,您能做的最好的事情就是通过捕获套接字 EINTR 错误并继续循环来主动忽略该问题:

import errno

try:
    # do something
    value = conn.recv(2048)
except socket.error as (code, msg):
    if code != errno.EINTR:
        raise
<小时/>

避免 C-c 中断读取问题的替代解决方案是使用并行执行,在例程中读取套接字,并在另一个套接字上处理用户输入:

import asyncio

async def camera_task(has_ended, filename):
    camera = videosensor.VideoSensor(filename)

    try:
        while not has_ended.is_set():
            location = camera.get_register()
            #...
            #More irrelevant stuff is executed.
            #...
            await asyncio.sleep(0.01)
    finally:
        #This code has to be executed after exiting while loop
        camera_shutdown(camera)

async def input_task(shall_end):
    while True:
        i = input("Press 'q' to stop the script…")
        if i == 'q':
            shall_end.set()

def main():
    filename = …
    #
    end_event = asyncio.Event()
    asyncio.Task(camera_task(end_event, filename))
    asyncio.Task(input_task(end_event))
    asyncio.get_event_loop().run_forever()

或使用 threading

import threading, time

def camera_task(has_ended, filename):
    camera = videosensor.VideoSensor(filename)

    try:
        while not has_ended.is_set():
            location = camera.get_register()
            #...
            #More irrelevant stuff is executed.
            #...
            time.sleep(0.01)
    finally:
        #This code has to be executed after exiting while loop
        camera_shutdown(camera)

def input_task(shall_end):
    while True:
        i = input("Press 'q' to stop the script…")
        if i == 'q':
            shall_end.set()

def main():
    filename = …
    #
    end_event = threading.Event()
    threads = [
        threading.Thread(target=camera_task, args=(end_event, filename)),
        threading.Thread(target=input_task, args=(end_event,))
    ]
    # start threads
    for thread in threads:
        thread.start()
    # wait for them to end
    for thread in threads:
        thread.join()

或使用 multiprocessing :

import multiprocessing, time

def camera_task(has_ended, filename):
    camera = videosensor.VideoSensor(filename)

    try:
        while not has_ended.is_set():
            location = camera.get_register()
            #...
            #More irrelevant stuff is executed.
            #...
            time.sleep(0.01)
    finally:
        #This code has to be executed after exiting while loop
        camera_shutdown(camera)

def input_task(shall_end):
    while True:
        i = input("Press 'q' to stop the script…")
        if i == 'q':
            shall_end.set()

def main():
    filename = …
    #
    end_event = multiprocessing.Event()
    processes = [
        multiprocessing.Process(target=camera_task, args=(end_event, filename)),
        multiprocessing.Process(target=input_task, args=(end_event,))
    ]
    # start processes
    for process in processes:
        process.start()
    # wait for them to end
    for process in processes:
        process.join()

disclaimer: those codes are untested, and there might be some typos or little errors, but I believe the overall logic should be 👌

关于python - 完成当前迭代后,如何结束带有套接字操作的无限循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41015323/

相关文章:

Linux 中断并发

python - 张量板重复标志错误

python - 如何从列表中删除索引列表

c++ - IPv4 和 IPv6 之间的混合模式通信

linux - 如果一台计算机更改了我们要向其发送数据的 IP 地址,TCP/IP 应该怎么做?

linux - 在 SATA AHCI 中禁用命令完成合并 (CCC)

python - 在 Python/Ubuntu 18.04 LTS 上安装 PCL 库

python - Pandas 根据其他列中的值更改列中的值

c - 有没有办法减少套接字发送缓冲区大小的最小下限?

assembly - 为什么每当我尝试使用中断时,我的 masm32 程序就会崩溃?