在 Python 中使用信号超时



我试图防止我的UDP客户端程序在服务器丢失数据包的情况下永远等待。我想使用信号来实现这一点。我的代码是:

def handler(signum):
raise TimeoutException("Timeout occured!")
signal.signal(signal.SIGALRM, sig_alarm)
sock.sendto(data,serv)
signal.alarm(5)
try:
received_time, servaddr = sock.recvfrom(size)
except TimeoutException:
print "timeout"
signal.alarm(0)

在远程服务器关闭的实例中运行此代码时,出现以下错误:

global name 'TimeoutException' is not defined

我假设程序没有"看到"我的处理程序。可能是什么原因造成的?

Python 2 或 Python 3 标准库中都没有TimeoutException异常类型。在 Python 3.3 及更高版本中,当操作系统调用在系统中超时(对应于errno设置为ETIMEDOUT值(时,会引发一种TimeoutError类型。但是,我不建议您自己提高此值,因为它的特定目的是响应操作系统返回的超时。

正确使用signal.signal

在您的注释中,在定义自定义超时异常类型后,您指示出现了进一步的错误:handler() takes exactly 1 argument (2 given).

发生这种情况是因为您的信号处理程序不符合signal包所期望的信号处理程序函数的定义(Python 3 的文档,但与 Python 2 相同(:

signal.signal(signum, handler)

将信号信号的处理程序设置为函数处理程序...处理程序使用两个参数调用:信号号和当前堆栈帧

若要解决此问题,请调整自定义信号处理程序的定义,以接收堆栈帧作为第二个参数。您需要在函数调用中接受这一点,正如标准库所期望的那样,但您不需要对传入的值执行任何操作。

def handler(signum, frame):
raise TimeoutException("Timeout occurred!")

更好的方法?使用socket.settimeout

socket库中有内置支持您要完成的任务:套接字对象的settimeout方法。我建议在你的代码中使用它,而不是试图重新发明轮子;它在抽象实现细节的同时声明意图,并具有内置的异常类型(socket.timeout(,您可以捕获以确定何时发生超时。

使用此方法,您只需在进行可能超时的阻止调用之前在套接字上调用socket.settimeout(5)。您还可以在打开应用程序中的第一个套接字之前,使用socket.setdefaulttimeout在所有套接字上设置默认超时。


TimeoutException最初是从哪里来的?

显然,您对它的使用可能来自任何地方。但是,我注意到Selenium中有一个TimeoutException,这是一个广泛使用的Python库,用于自动化浏览器。它被广泛使用,与Selenium相关的示例/问答很常见,所以如果你找到文档或示例,让你相信这是标准库中存在的异常类型,而它实际上是特定于该库的类型,我不会感到惊讶。似乎与硒相关的任何内容都不适用于您当前的用例。

对于此错误:global name 'TimeoutException' is not defined这意味着你必须声明你的自定义异常..这样做的简单方法是将其添加到你的代码中:

class TimeoutException(Exception): pass

要提到的一件事是,Selenium有一个名为TimeoutException的异常,它不是标准库中存在的异常类型,而是特定于Selenium库的异常类型:

from selenium.common.exceptions import TimeoutException

最后你会遇到另一个错误,因为你的信号处理程序必须接收堆栈帧作为第二个参数(处理程序使用两个参数调用:信号号和当前堆栈帧(:

def handler(signum, frame): raise TimeoutException("Timeout occurred!")

请阅读文档最小示例程序中的以下示例

最新更新