Тайм-аут для клиентских запросов xmlrpclib

Я использую Python xmlrpclib для выполнения запросов к службе xml-rpc.

Есть ли способ установить тайм-аут клиента, чтобы мои запросы не зависали вечно, когда сервер недоступен?

Я знаю, что могу глобально установить время ожидания сокета с помощью socket.setdefaulttimeout(), но это нежелательно.


person Corey Goldberg    schedule 11.03.2010    source источник


Ответы (5)


Чистый подход заключается в определении и использовании пользовательского транспорта, например: ! это будет работать только для python2.7!

import xmlrpclib, httplib

class TimeoutTransport(xmlrpclib.Transport):
    timeout = 10.0
    def set_timeout(self, timeout):
        self.timeout = timeout
    def make_connection(self, host):
        h = httplib.HTTPConnection(host, timeout=self.timeout)
        return h

t = TimeoutTransport()
t.set_timeout(20.0)
server = xmlrpclib.Server('http://time.xmlrpc.com/RPC2', transport=t)

Пример определения и использования пользовательского транспорта приведен в . docs, хотя он использует его для другой цели (доступ через прокси, а не установку времени ожидания), этот код в основном вдохновлен этим примером.

person Alex Martelli    schedule 11.03.2010
comment
этот пример не работает на python 2.5, 2.6 (экземпляр TimeoutTransport не имеет атрибута «прокси»), а также httplib.HTTP не имеет значения времени ожидания. - person Ib33X; 10.11.2010
comment
Я заметил, что исходный метод Transport.make_connection в Python 2.7 имеет больше логики для обработки поддержки активности, дополнительных заголовков и т. д., и что он также использует httplib.HTTPConnection, а не httplib.HTTP. Я не знаю, важно ли это в типичных случаях использования, но я решил скопировать исходный код и изменить его, чтобы использовать тайм-ауты, как показано в ответе выше. - person Pekka Klärck; 24.09.2014

doh, чтобы это работало в python2.6+, сделайте следующее:

class HTTP_with_timeout(httplib.HTTP):
    def __init__(self, host='', port=None, strict=None, timeout=5.0):
        if port == 0: port = None
        self._setup(self._connection_class(host, port, strict, timeout=timeout))

    def getresponse(self, *args, **kw):
        return self._conn.getresponse(*args, **kw)

class TimeoutTransport(xmlrpclib.Transport):
    timeout = 10.0
    def set_timeout(self, timeout):
        self.timeout = timeout
    def make_connection(self, host):
        h = HTTP_with_timeout(host, timeout=self.timeout)
        return h
person user755236    schedule 16.05.2011

Почему нет:

class TimeoutTransport(xmlrpclib.Transport):

def setTimeout(self, timeout):
    self._timeout = timeout

def make_connection(self, host):
    return httplib.HTTPConnection(host, timeout=self._timeout)

?

В конце концов, HTTP и HTTPS кажутся не более чем классами совместимости для более старых версий Python.

person ubik    schedule 28.06.2011

Альтернативная реализация, совместимая с python 2.7, будет выглядеть следующим образом (с комментарием, содержащим то, что вам нужно, если вы используете python 2.6):

import socket
import xmlrpclib

class TimeoutTransport (xmlrpclib.Transport):
    """
    Custom XML-RPC transport class for HTTP connections, allowing a timeout in
    the base connection.
    """

    def __init__(self, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, use_datetime=0):
        xmlrpclib.Transport.__init__(self, use_datetime)
        self._timeout = timeout

    def make_connection(self, host):
        # If using python 2.6, since that implementation normally returns the 
        # HTTP compatibility class, which doesn't have a timeout feature.
        #import httplib
        #host, extra_headers, x509 = self.get_host_info(host)
        #return httplib.HTTPConnection(host, timeout=self._timeout)

        conn = xmlrpclib.Transport.make_connection(self, host)
        conn.timeout = self._timeout
        return conn

# Example use
t = TimeoutTransport(timeout=10)
server = xmlrpclib.ServerProxy('http://time.xmlrpc.com/RPC2', transport=t)

Использование суперметода позволит базовой реализации версии 2.7 поддерживать заданную им функциональность поддержания активности HTTP/1.1.

Следует отметить, что если вы пытаетесь использовать XML-RPC по соединению/адресу https, вместо этого замените ссылки xmlrpc.SafeTransport на xmlrpc.Transport, а если вы используете реализацию 2.6, используйте httplib.HTTPSConnection.

person purg    schedule 06.06.2013

Если кто-то пытается сделать это в Python 3+ и использует контекст kwarg (в моем случае, чтобы разрешить подключение к самозаверяющим SSL-сертификатам), для меня работает следующий код

class TimeoutTransport (xmlrpc.client.SafeTransport):
    def __init__(self, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, context=None, use_datetime=0):
        xmlrpc.client.Transport.__init__(self, use_datetime)
        self._timeout = timeout
        self.context = context

    def make_connection(self, host):
        conn = xmlrpc.client.SafeTransport.make_connection(self, host)
        conn.timeout = self._timeout
        return conn

А затем позвоните с помощью:

 url = "https://localhost:8080/RPC2"
 t = TimeoutTransport(timeout=2, context=ssl._create_unverified_context())
 xml_conn = xmlrpc.client.ServerProxy(
        url,
        transport=t
    )
person ReturnOfTheRazz    schedule 26.05.2020