【问题标题】:Set timeout for xmlrpclib.ServerProxy为 xmlrpclib.ServerProxy 设置超时
【发布时间】:2010-09-27 04:57:49
【问题描述】:

我正在使用 xmlrpclib.ServerProxy 对远程服务器进行 RPC 调用。如果没有与服务器的网络连接,则默认需要 10 秒才能将 socket.gaierror 返回给我的程序。

在没有网络连接的情况下进行开发或远程服务器关闭时,这很烦人。有没有办法更新我的 ServerProxy 对象的超时时间?

我看不到一个明确的方法来访问套接字来更新它。

【问题讨论】:

    标签: python xml-rpc


    【解决方案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。
                猜你喜欢
                • 2010-10-10
                • 2017-07-31
                • 1970-01-01
                • 2010-12-21
                • 2015-12-17
                • 2019-03-27
                • 2011-12-14
                • 2011-01-16
                • 2011-07-10
                相关资源
                最近更新 更多