На этом шаге мы рассмотрим особенности создания и использования 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 стоит знать - на случай, если вам понадобится быстро и начерно сделать систему удаленного вызова процедур. Часто этого простого решения вполне достаточно.
На следующем шаге мы рассмотрим простое взаимодействие между интерпретаторами.