为 xmlrpclib.ServerProxy 设置超时
Posted
技术标签:
【中文标题】为 xmlrpclib.ServerProxy 设置超时【英文标题】:Set timeout for xmlrpclib.ServerProxy 【发布时间】:2010-09-27 04:57:49 【问题描述】:我正在使用 xmlrpclib.ServerProxy 对远程服务器进行 RPC 调用。如果没有与服务器的网络连接,则默认需要 10 秒才能将 socket.gaierror 返回给我的程序。
在没有网络连接的情况下进行开发或远程服务器关闭时,这很烦人。有没有办法更新我的 ServerProxy 对象的超时时间?
我看不到一个明确的方法来访问套接字来更新它。
【问题讨论】:
【参考方案1】:干净的非全局版本。
import xmlrpclib
import httplib
class TimeoutHTTPConnection(httplib.HTTPConnection):
def connect(self):
httplib.HTTPConnection.connect(self)
self.sock.settimeout(self.timeout)
class TimeoutHTTP(httplib.HTTP):
_connection_class = TimeoutHTTPConnection
def set_timeout(self, timeout):
self._conn.timeout = timeout
class TimeoutTransport(xmlrpclib.Transport):
def __init__(self, timeout=10, *l, **kw):
xmlrpclib.Transport.__init__(self, *l, **kw)
self.timeout = timeout
def make_connection(self, host):
conn = TimeoutHTTP(host)
conn.set_timeout(self.timeout)
return conn
class TimeoutServerProxy(xmlrpclib.ServerProxy):
def __init__(self, uri, timeout=10, *l, **kw):
kw['transport'] = TimeoutTransport(
timeout=timeout, use_datetime=kw.get('use_datetime', 0))
xmlrpclib.ServerProxy.__init__(self, uri, *l, **kw)
if __name__ == "__main__":
s = TimeoutServerProxy('http://127.0.0.1:9090', timeout=2)
s.dummy()
【讨论】:
非常适合我,Debian 上的 Python2.5。顺便说一句,你有一个虚假的'。导入中的字符,并且未使用“导入套接字”。 在 Python 2.7 上不适合我。当我进行 RPC 调用时,我收到错误AttributeError: TimeoutHTTP instance has no attribute 'getresponse'
get AttributeError: module 'http.client' has no attribute 'HTTPClient' when I migrate to python3.【参考方案2】:
我想要一个小而干净但又明确的版本,所以根据这里的所有其他答案,这就是我想出的:
import xmlrpclib
class TimeoutTransport(xmlrpclib.Transport):
def __init__(self, timeout, use_datetime=0):
self.timeout = timeout
# xmlrpclib uses old-style classes so we cannot use super()
xmlrpclib.Transport.__init__(self, use_datetime)
def make_connection(self, host):
connection = xmlrpclib.Transport.make_connection(self, host)
connection.timeout = self.timeout
return connection
class TimeoutServerProxy(xmlrpclib.ServerProxy):
def __init__(self, uri, timeout=10, transport=None, encoding=None, verbose=0, allow_none=0, use_datetime=0):
t = TimeoutTransport(timeout)
xmlrpclib.ServerProxy.__init__(self, uri, t, encoding, verbose, allow_none, use_datetime)
proxy = TimeoutServerProxy(some_url)
一开始我没有意识到 xmlrpclib
有老式的类,所以我发现它对它的评论很有用,否则一切都应该是不言自明的。
我不明白为什么httplib.HTTP
也必须被子类化,如果有人能在这方面启发我,请这样做。上述解决方案已尝试并有效。
【讨论】:
【参考方案3】:以下示例适用于 Python 2.7.4。
import xmlrpclib
from xmlrpclib import *
import httplib
def Server(url, *args, **kwargs):
t = TimeoutTransport(kwargs.get('timeout', 20))
if 'timeout' in kwargs:
del kwargs['timeout']
kwargs['transport'] = t
server = xmlrpclib.Server(url, *args, **kwargs)
return server
TimeoutServerProxy = Server
class TimeoutTransport(xmlrpclib.Transport):
def __init__(self, timeout, use_datetime=0):
self.timeout = timeout
return xmlrpclib.Transport.__init__(self, use_datetime)
def make_connection(self, host):
conn = xmlrpclib.Transport.make_connection(self, host)
conn.timeout = self.timeout
return connrpclib.Server(url, *args, **kwargs)
【讨论】:
【参考方案4】:基于 antonylesuisse 的那个,但是在 Python 2.7.5 上工作,解决了这个问题:AttributeError: TimeoutHTTP instance has no attribute 'getresponse'
class TimeoutHTTP(httplib.HTTP):
def __init__(self, host='', port=None, strict=None,
timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
if port == 0:
port = None
self._setup(self._connection_class(host, port, strict, timeout))
def getresponse(self, *args, **kw):
return self._conn.getresponse(*args, **kw)
class TimeoutTransport(xmlrpclib.Transport):
def __init__(self, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, *l, **kw):
xmlrpclib.Transport.__init__(self, *l, **kw)
self.timeout=timeout
def make_connection(self, host):
host, extra_headers, x509 = self.get_host_info(host)
conn = TimeoutHTTP(host, timeout=self.timeout)
return conn
class TimeoutServerProxy(xmlrpclib.ServerProxy):
def __init__(self, uri, timeout= socket._GLOBAL_DEFAULT_TIMEOUT, *l, **kw):
kw['transport']=TimeoutTransport(timeout=timeout, use_datetime=kw.get('use_datetime',0))
xmlrpclib.ServerProxy.__init__(self, uri, *l, **kw)
proxy = TimeoutServerProxy('http://127.0.0.1:1989', timeout=30)
print proxy.test_connection()
【讨论】:
【参考方案5】:这里是另一个使用 Python 的 with
语句的智能且非常 pythonic 的解决方案:
import socket
import xmlrpc.client
class MyServerProxy:
def __init__(self, url, timeout=None):
self.__url = url
self.__timeout = timeout
self.__prevDefaultTimeout = None
def __enter__(self):
try:
if self.__timeout:
self.__prevDefaultTimeout = socket.getdefaulttimeout()
socket.setdefaulttimeout(self.__timeout)
proxy = xmlrpc.client.ServerProxy(self.__url, allow_none=True)
except Exception as ex:
raise Exception("Unable create XMLRPC-proxy for url '%s': %s" % (self.__url, ex))
return proxy
def __exit__(self, type, value, traceback):
if self.__prevDefaultTimeout is None:
socket.setdefaulttimeout(self.__prevDefaultTimeout)
这个类可以这样使用:
with MyServerProxy('http://1.2.3.4', 20) as proxy:
proxy.dummy()
【讨论】:
【参考方案6】:这是来自http://code.activestate.com/recipes/473878/的逐字副本
def timeout(func, args=(), kwargs=, timeout_duration=1, default=None):
import threading
class InterruptableThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.result = None
def run(self):
try:
self.result = func(*args, **kwargs)
except:
self.result = default
it = InterruptableThread()
it.start()
it.join(timeout_duration)
if it.isAlive():
return default
else:
return it.result
【讨论】:
【参考方案7】:以下代码可在 Python 2.7(可能适用于其他 2.x 版本的 Python)上运行而不会引发 AttributeError,实例没有属性“getresponse”。
class TimeoutHTTPConnection(httplib.HTTPConnection):
def connect(self):
httplib.HTTPConnection.connect(self)
self.sock.settimeout(self.timeout)
class TimeoutHTTP(httplib.HTTP):
_connection_class = TimeoutHTTPConnection
def set_timeout(self, timeout):
self._conn.timeout = timeout
class TimeoutTransport(xmlrpclib.Transport):
def __init__(self, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, *args, **kwargs):
xmlrpclib.Transport.__init__(self, *args, **kwargs)
self.timeout = timeout
def make_connection(self, host):
if self._connection and host == self._connection[0]:
return self._connection[1]
chost, self._extra_headers, x509 = self.get_host_info(host)
self._connection = host, httplib.HTTPConnection(chost)
return self._connection[1]
transport = TimeoutTransport(timeout=timeout)
xmlrpclib.ServerProxy.__init__(self, uri, transport=transport, allow_none=True)
【讨论】:
看起来像不完整的sn-p。【参考方案8】:基于 antonylesuisse 的一个工作版本(在 python >= 2.6 上)。
# -*- coding: utf8 -*-
import xmlrpclib
import httplib
import socket
class TimeoutHTTP(httplib.HTTP):
def __init__(self, host='', port=None, strict=None,
timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
if port == 0:
port = None
self._setup(self._connection_class(host, port, strict, timeout))
class TimeoutTransport(xmlrpclib.Transport):
def __init__(self, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, *args, **kwargs):
xmlrpclib.Transport.__init__(self, *args, **kwargs)
self.timeout = timeout
def make_connection(self, host):
host, extra_headers, x509 = self.get_host_info(host)
conn = TimeoutHTTP(host, timeout=self.timeout)
return conn
class TimeoutServerProxy(xmlrpclib.ServerProxy):
def __init__(self, uri, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
*args, **kwargs):
kwargs['transport'] = TimeoutTransport(timeout=timeout,
use_datetime=kwargs.get('use_datetime', 0))
xmlrpclib.ServerProxy.__init__(self, uri, *args, **kwargs)
【讨论】:
【参考方案9】:更直接的解决方案是: http://www.devpicayune.com/entry/200609191448
import xmlrpclib
import socket
x = xmlrpclib.ServerProxy('http:1.2.3.4')
socket.setdefaulttimeout(10) #set the timeout to 10 seconds
x.func_name(args) #times out after 10 seconds
socket.setdefaulttimeout(None) #sets the default back
【讨论】:
socket如何应用于xmlrpclib?我们永远不会在 x 上设置套接字。 @ashchristopher:我没有测试过这段代码,但看起来 setdefaulttimeout 是一个全局默认值。所以如果 xmlrpclib 没有设置任何特定的超时值,它可能会使用全局默认值。 @MiniQuark:正确,这是一个全局默认值(无),这意味着新的套接字对象没有超时。 setdefaulttimeout 函数的优点是它适用于 HTTPS/SSL 套接字,而其他发布的示例仅适用于 HTTP。 @Jeff Bauer:使用 HTTP 的社区 wiki 示例也可以通过子类化 HTTPSConnection、HTTPS 和 SafeTransport 来完成。这应该以同样的方式工作。 绝对是我的代码的赢家。与其他人建议的添加 3 个类相比,我添加了 2 行并完成了。 TL;顺便说一句,DR。以上是关于为 xmlrpclib.ServerProxy 设置超时的主要内容,如果未能解决你的问题,请参考以下文章