Установить тайм-аут для xmlrpclib.ServerProxy

Я использую xmlrpclib.ServerProxy для выполнения вызовов RPC на удаленный сервер. Если нет сетевого подключения к серверу, по умолчанию требуется 10 секунд, чтобы вернуть socket.gaierror в мою программу.

Это раздражает при разработке без подключения к сети или если удаленный сервер не работает. Есть ли способ обновить тайм-аут моего объекта ServerProxy?

Я не вижу четкого способа получить доступ к сокету для его обновления.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
24
0
20 091
9

Ответы 9

Вот дословная копия из 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

Более простое решение находится по адресу: 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

Как сокет применяется к xmlrpclib? Мы никогда не устанавливаем сокет на x.

ashchristopher 26.11.2009 18:33

@ashchristopher: я не тестировал этот код, но похоже, что setdefaulttimeout является глобальным значением по умолчанию. Поэтому, если xmlrpclib не устанавливает какое-либо конкретное значение тайм-аута, он, вероятно, будет использовать глобальное значение по умолчанию.

MiniQuark 18.10.2010 16:02

@MiniQuark: Верно, это глобальное значение по умолчанию (Нет), что означает, что у новых объектов сокета нет тайм-аута. Функция setdefaulttimeout имеет то преимущество, что она работает для сокетов HTTPS / SSL, тогда как другие опубликованные примеры работают только с HTTP.

Jeff Bauer 29.01.2011 00:41

@Jeff Bauer: пример вики сообщества с HTTP также можно сделать с подклассом HTTPSConnection, HTTPS и SafeTransport. Это должно работать точно так же.

housemaister 08.04.2011 17:24

Определенно победитель для моего кода. Я добавил 2 строки и сделал по сравнению с добавлением 3 классов, которые предлагают другие. TL; DR между прочим.

Giszmo 26.07.2013 05:20

чистая неглобальная версия.

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()

У меня отлично работает, Python2.5 на Debian. Кстати, у вас фальшивая ''. символ в импорте, а «сокет импорта» не используется.

Jonathan Hartley 05.10.2010 19:46

У меня не работает на Python 2.7. Когда я выполняю вызов RPC, я получаю сообщение об ошибке AttributeError: TimeoutHTTP instance has no attribute 'getresponse'

AFoglia 03.08.2011 11:54

get AttributeError: модуль http.client не имеет атрибута HTTPClient при переходе на python3.

LetsOMG 29.08.2018 01:51

На основе версии от 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)

Вот код, который работает на Python 2.7 (возможно, для других версий Python 2.x) без повышения 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)

Похоже, фрагмент неполный.

Denis Barmenkov 20.07.2012 17:01

Вот еще одно умное и очень питонический решение с использованием оператора Python with:

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()

Следующий пример работает с 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)

На основе одного из 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()

Я хотел небольшую, чистую, но также явную версию, поэтому, основываясь на всех других ответах здесь, вот что я придумал:

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 также должен быть подклассом, если кто-то может просветить меня по этому поводу, пожалуйста, сделайте это. Вышеупомянутое решение проверено и работает.

Другие вопросы по теме