Шаг 209.
Python: сборник рецептов. Сети и веб-программирование. Реализация простого удаленного вызова процедуры через XML-RPC

    На этом шаге мы рассмотрим особенности создания и использования XML-RPC-сервиса.

Задача

    Вам нужен простой способ выполнить функции или методы в программах Python, работающих на удаленных компьютерах.

Решение

    Вероятно, самый легкий способ реализовать простой механизм вызова удаленной процедуры - это XML-RPC. Вот пример простого сервера, который реализует простое хранилище типа "ключ-значение":

from xmlrpc.server import SimpleXMLRPCServer


class KeyValueServer:
    _rpc_methods_ = ['get', 'set', 'delete', 'exists', 'keys']

    def __init__(self, address):
        self._data = {}
        self._serv = SimpleXMLRPCServer(address, allow_none=True)
        for name in self._rpc_methods_:
            self._serv.register_function(getattr(self, name))

    def get(self, name):
        return self._data[name]

    def set(self, name, value):
        self._data[name] = value

    def delete(self, name):
        del self._data[name]

    def exists(self, name):
        return name in self._data

    def keys(self):
        return list(self._data)

    def serve_forever(self):
        self._serv.serve_forever()


# Пример
if __name__ == '__main__':
    kvserv = KeyValueServer(('', 15000))
    kvserv.serve_forever()
Архив с этим файлом можно взять здесь.

    Вот как вы можете обращаться к серверу удаленно из клиента:

>>> from xmlrpc.client import ServerProxy
>>> s = ServerProxy('http://localhost:15000', allow_none=True)
>>> s.set('foo', 'bar')
>>> s.set('spam', [1, 2, 3])
>>> s.keys()
['foo', 'spam']
>>> s.get('foo')
'bar'
>>> s.get('spam')
[1, 2, 3]
>>> s.delete('spam')
>>> s.exists('spam')
False
>>> 


Обсуждение

    XML-RPC может быть чрезвычайно простым способом реализовать сервис для удаленного вызова процедур. Вам нужно только создать экземпляр сервера, зарегистрировать функции с использованием метода register_functions() и запустить его с помощью метода serve_forever(). Данный рецепт упаковывает все это в класс, но такого требования на самом деле нет. Например, вы можете создать сервер самостоятельно:

from xmlrpc.server import SimpleXMLRPCServer


def add(x,y):
    return x+y

serv = SimpleXMLRPCServer(('', 15000))
serv.register_function(add)
serv.serve_forever()

    Функции, которые показываются наружу через XML-RPC, работают только с некоторыми типами данных, такими как строки, числа, списки и словари. Для всего остального нужно будет поизучать тему. Например, если вы передадите экземпляр через XML-RPC, то будет обработан только словарь экземпляра:

>>> class Point:
	def __init__(self, x, y):
		self.x = x
		self.y = y

		
>>> p = Point(2, 3) 
>>> s.set('foo', p)
>>> s.get('foo') 
{'x': 2, 'y': 3}

    Обработка бинарных данных также немного отличается от того, чего вы могли бы ожидать:

>>> s.set('foo', b'Hello World')
>>> s.get('foo')
<xmlrpc.client.Binary object at 0x10131d410>
>>> _.data
b'Hello World'
>>>

    Как общее правило: наверное, не стоит показывать XML-RPC-сервис всему миру в качестве публичного API. Этот подход хорошо работает только для внутренних сетей, где вы можете писать простые распределенные программы, работающие на нескольких компьютерах.

    Недостаток XML-RPC - это его производительность. Реализация SimpleXMLRPCServer является однопоточной, что неприемлемо для крупных приложений (хотя и его можно запускать многопоточно - см. 205 шаг). Также, поскольку XML-RPC сериализует все данные в XML, он будет по определению медленнее других подходов. Однако преимущество этой кодировки состоит в том, что ее понимают очень многие языки программирования. Поэтому клиенты, написанные не на Python, смогут обращаться к вашему сервису.

    Несмотря на свои ограничения, о XML-RPC стоит знать - на случай, если вам понадобится быстро и начерно сделать систему удаленного вызова процедур. Часто этого простого решения вполне достаточно.

    На следующем шаге мы рассмотрим простое взаимодействие между интерпретаторами.




Предыдущий шаг Содержание Следующий шаг