xmlrpc.client — XML-RPC 클라이언트 액세스

소스 코드: Lib/xmlrpc/client.py


XML-RPC는 HTTP(S)를 통해 전달된 XML을 트랜스포트로 사용하는 원격 프로시저 호출(Remote Procedure Call) 방법입니다. 이를 통해, 클라이언트는 원격 서버에서 매개 변수를 사용하여 메서드를 호출하고 (서버는 URI로 이름이 지정됩니다) 구조화된 데이터를 돌려받을 수 있습니다. 이 모듈은 XML-RPC 클라이언트 코드 작성을 지원합니다; 적합한 파이썬 객체와 전송 회선 상의 XML 간 변환의 모든 세부 사항을 처리합니다.

경고

xmlrpc.client 모듈은 악의적으로 구성된 데이터로부터 안전하지 않습니다. 신뢰할 수 없거나 인증되지 않은 데이터를 구문 분석해야 하면 XML 취약점을 참조하십시오.

버전 3.5에서 변경: HTTPS URI의 경우, xmlrpc.client는 이제 기본적으로 필요한 모든 인증서와 호스트명 확인을 수행합니다.

class xmlrpc.client.ServerProxy(uri, transport=None, encoding=None, verbose=False, allow_none=False, use_datetime=False, use_builtin_types=False, *, headers=(), context=None)

ServerProxy 인스턴스는 원격 XML-RPC 서버와의 통신을 관리하는 객체입니다. 필수적인 첫 번째 인자는 URI(Uniform Resource Indicator)이며 일반적으로 서버의 URL입니다. 선택적인 두 번째 인자는 트랜스포트 팩토리 인스턴스입니다; 기본적으로 https: URL의 경우는 내부 SafeTransport 인스턴스이고 그렇지 않으면 내부 HTTP Transport 인스턴스입니다. 선택적 세 번째 인자는 인코딩이며, 기본적으로 UTF-8입니다. 선택적 네 번째 인자는 디버깅 플래그입니다.

The following parameters govern the use of the returned proxy instance. If allow_none is true, the Python constant None will be translated into XML; the default behaviour is for None to raise a TypeError. This is a commonly used extension to the XML-RPC specification, but isn’t supported by all clients and servers; see http://ontosys.com/xml-rpc/extensions.php for a description. The use_builtin_types flag can be used to cause date/time values to be presented as datetime.datetime objects and binary data to be presented as bytes objects; this flag is false by default. datetime.datetime, bytes and bytearray objects may be passed to calls. The headers parameter is an optional sequence of HTTP headers to send with each request, expressed as a sequence of 2-tuples representing the header name and value. (e.g. [('Header-Name', 'value')]). The obsolete use_datetime flag is similar to use_builtin_types but it applies only to date/time values.

버전 3.3에서 변경: use_builtin_types 플래그가 추가되었습니다.

버전 3.8에서 변경: headers 매개 변수가 추가되었습니다.

HTTP와 HTTPS 트랜스포트는 모두 HTTP 기본 인증(Basic Authentication)을 위한 URL 구문 확장을 지원합니다: http://user:pass@host:port/path. user:pass 부분은 HTTP ‘Authorization’ 헤더로 base64 인코딩되고, XML-RPC 메서드를 호출할 때 연결 프로세스의 일부로 원격 서버로 전송됩니다. 원격 서버가 기본 인증 사용자와 비밀번호를 요구할 때만 이를 사용해야 합니다. HTTPS URL이 제공되면, contextssl.SSLContext 일 수 있고 하부 HTTPS 연결의 SSL 설정을 구성합니다.

반환된 인스턴스는 원격 서버에서 해당 RPC 호출을 호출하는 데 사용할 수 있는 메서드가 있는 프락시 객체입니다. 원격 서버가 인트로스펙션(introspection) API를 지원하면, 프락시를 사용하여 원격 서버에서 지원하는 메서드를 조회하고 (서비스 검색, service discovery) 다른 서버 관련 메타 데이터를 가져올 수 있습니다.

적합한 형(예를 들어 XML을 통해 마샬링 할 수 있는 형)에는 다음이 포함됩니다 (별도로 표시된 경우를 제외하고는 같은 파이썬 형으로 역마샬링 됩니다):

XML-RPC 형

파이썬 형

boolean

bool

int, i1, i2, i4, i8 또는 biginteger

-2147483648에서 2147483647 범위의 int. 값은 <int> 태그를 얻습니다.

double이나 float

float. 값은 <double> 태그를 얻습니다.

string

str

array

적합한 요소를 포함하는 listtuple. 배열은 리스트로 반환됩니다.

struct

dict. 키는 문자열이어야 하며, 값은 적합한 형일 수 있습니다. 사용자 정의 클래스의 객체를 전달할 수 있습니다; __dict__ 어트리뷰트만 전송됩니다.

dateTime.iso8601

DateTime이나 datetime.datetime. 반환되는 형은 use_builtin_typesuse_datetime 플래그 값에 따라 다릅니다.

base64

Binary, bytes 또는 bytearray. 반환되는 형은 use_builtin_types 플래그의 값에 따라 다릅니다.

nil

None 상수. allow_none이 참일 때만 전달이 허용됩니다.

bigdecimal

decimal.Decimal. 반환되는 형 전용.

이것이 XML-RPC가 지원하는 데이터형의 전체 집합입니다. 메서드 호출은 XML-RPC 서버 에러를 알리는 데 사용되는 특수 Fault 인스턴스나 HTTP/HTTPS 전송 계층의 에러를 알리는 데 사용되는 ProtocolError를 발생시킬 수도 있습니다. FaultProtocolError는 모두 Error라는 베이스 클래스에서 파생됩니다. xmlrpc 클라이언트 모듈은 현재 내장형의 서브 클래스 인스턴스를 마샬링 하지 않음에 유의하십시오.

문자열을 전달할 때, <, >&와 같은 XML에 특수한 문자는 자동으로 이스케이프 됩니다. 그러나, 0에서 31 사이의 ASCII 값을 가진 제어 문자(물론 탭, 줄 넘김 및 캐리지 리턴은 제외하고)와 같이 문자열에 XML에서 허용되지 않는 문자가 없도록 확인하는 것은 호출자의 책임입니다; 이렇게 하지 않으면 XML 형식이 잘못된 XML-RPC 요청이 발생합니다. XML-RPC를 통해 임의의 바이트열을 전달해야 하면, bytesbytearray 클래스 또는 아래 설명된 Binary 래퍼 클래스를 사용하십시오.

Server는 이전 버전과의 호환성을 위해 ServerProxy의 별칭으로 유지됩니다. 새 코드는 ServerProxy를 사용해야 합니다.

버전 3.5에서 변경: context 인자를 추가했습니다.

버전 3.6에서 변경: Added support of type tags with prefixes (e.g. ex:nil). Added support of unmarshalling additional types used by Apache XML-RPC implementation for numerics: i1, i2, i8, biginteger, float and bigdecimal. See https://ws.apache.org/xmlrpc/types.html for a description.

더 보기

XML-RPC HOWTO

여러 언어로 된 XML-RPC 연산과 클라이언트 소프트웨어에 대한 훌륭한 설명. XML-RPC 클라이언트 개발자가 알아야 할 거의 모든 것이 포함되어 있습니다.

XML-RPC Introspection

인트로스펙션을 위한 XML-RPC 프로토콜 확장을 설명합니다.

XML-RPC Specification

공식 명세.

ServerProxy 객체

ServerProxy 인스턴스에는 XML-RPC 서버가 받아들이는 각 원격 프로시저 호출에 해당하는 메서드가 있습니다. 메서드를 호출하면 RPC를 수행하는데, 이름과 인자 서명 모두로 디스패치 됩니다 (예를 들어 같은 메서드 이름이 여러 인자 서명으로 오버로드 될 수 있습니다). RPC는 값을 반환하여 완료되는데, 값은 적합한 형으로 반환된 데이터이거나 에러를 나타내는 FaultProtocolError 객체일 수 있습니다.

XML 인트로스팩션 API를 지원하는 서버는 예약된 system 어트리뷰트 밑에 그룹화된 몇 가지 공통 메서드를 지원합니다:

ServerProxy.system.listMethods()

이 메서드는 문자열 리스트를 반환하는데, XML-RPC 서버가 지원하는 각 (system이 아닌) 메서드마다 하나씩 제공됩니다.

ServerProxy.system.methodSignature(name)

이 메서드는 하나의 매개 변수를 취하는데, XML-RPC 서버에 의해 구현된 메서드의 이름입니다. 이 메서드에 대해 가능한 서명의 배열을 반환합니다. 서명은 형의 배열입니다. 이 형 중 첫 번째는 메서드의 반환형이고 나머지는 매개 변수입니다.

다중 서명(즉 오버로딩)이 허용되므로, 이 메서드는 하나가 아닌 서명의 리스트를 반환합니다.

서명 자체는 메서드가 기대하는 최상위 매개 변수로 제한됩니다. 예를 들어, 메서드가 구조체 배열 하나를 매개 변수로 기대하고, 문자열을 반환하면, 서명은 단순히 “string, array”입니다. 세 개의 정수를 기대하고 문자열을 반환하면, 서명은 “string, int, int, int”입니다.

메서드에 서명이 정의되지 않으면, 배열이 아닌 값이 반환됩니다. 파이썬에서 이것은 반환된 값의 형이 리스트 이외의 어떤 것이 됨을 의미합니다.

ServerProxy.system.methodHelp(name)

이 메서드는 하나의 매개 변수를 취하는데, XML-RPC 서버에 의해 구현된 메서드의 이름입니다. 해당 메서드의 사용법을 기술하는 설명서 문자열을 반환합니다. 이러한 문자열이 없으면, 빈 문자열이 반환됩니다. 설명서 문자열에 HTML 마크업이 포함될 수 있습니다.

버전 3.5에서 변경: ServerProxy 인스턴스는 하부 트랜스포트를 닫기 위한 컨텍스트 관리자 프로토콜을 지원합니다.

다음은 실제 예입니다. 서버 코드:

from xmlrpc.server import SimpleXMLRPCServer

def is_even(n):
    return n % 2 == 0

server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(is_even, "is_even")
server.serve_forever()

이전 서버에 대한 클라이언트 코드:

import xmlrpc.client

with xmlrpc.client.ServerProxy("http://localhost:8000/") as proxy:
    print("3 is even: %s" % str(proxy.is_even(3)))
    print("100 is even: %s" % str(proxy.is_even(100)))

DateTime 객체

class xmlrpc.client.DateTime

이 클래스는 에포크(epoch) 이후의 초, 시간 튜플, ISO 8601 시간/날짜 문자열 또는 datetime.datetime으로 초기화될 수 있습니다. 주로 마샬링/역마샬링 코드 내부에서 사용하기 위해 지원되는, 다음과 같은 메서드가 있습니다:

decode(string)

인스턴스의 새 시간 값으로 문자열을 받아들입니다.

encode(out)

DateTime 항목의 XML-RPC 인코딩을 out 스트림 객체에 씁니다.

풍부한 비교와 __repr__() 메서드를 통해 특정 파이썬 내장 연산자도 지원합니다.

다음은 실제 예입니다. 서버 코드:

import datetime
from xmlrpc.server import SimpleXMLRPCServer
import xmlrpc.client

def today():
    today = datetime.datetime.today()
    return xmlrpc.client.DateTime(today)

server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(today, "today")
server.serve_forever()

이전 서버에 대한 클라이언트 코드:

import xmlrpc.client
import datetime

proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")

today = proxy.today()
# convert the ISO8601 string to a datetime object
converted = datetime.datetime.strptime(today.value, "%Y%m%dT%H:%M:%S")
print("Today: %s" % converted.strftime("%d.%m.%Y, %H:%M"))

Binary 객체

class xmlrpc.client.Binary

이 클래스는 바이트열 데이터(NUL을 포함할 수 있습니다)로 초기화될 수 있습니다. Binary 객체의 내용에 대한 기본 액세스는 어트리뷰트에 의해 제공됩니다:

data

Binary 인스턴스로 캡슐화된 바이너리 데이터. 데이터는 bytes 객체로 제공됩니다.

Binary 객체에는 주로 마샬링/역마샬링 코드 내부에서 사용하기 위해 지원되는 다음과 같은 메서드가 있습니다:

decode(bytes)

base64 bytes 객체를 받아들이고 인스턴스의 새 데이터로 디코딩합니다.

encode(out)

이 바이너리 항목의 XML-RPC base64 인코딩을 out 스트림 객체에 씁니다.

인코딩된 데이터에는 RFC 2045 섹션 6.8에 따라 76문자마다 줄 바꿈이 있는데, 이는 XML-RPC 명세가 작성될 때 사실상 표준 base64 명세였습니다.

__eq__()__ne__() 메서드를 통해 특정 파이썬 내장 연산자도 지원합니다.

바이너리 객체의 사용 예. XMLRPC를 통해 이미지를 전송할 것입니다:

from xmlrpc.server import SimpleXMLRPCServer
import xmlrpc.client

def python_logo():
    with open("python_logo.jpg", "rb") as handle:
        return xmlrpc.client.Binary(handle.read())

server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(python_logo, 'python_logo')

server.serve_forever()

클라이언트는 이미지를 가져와서 파일에 저장합니다:

import xmlrpc.client

proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
with open("fetched_python_logo.jpg", "wb") as handle:
    handle.write(proxy.python_logo().data)

Fault 객체

class xmlrpc.client.Fault

Fault 객체는 XML-RPC 결함 태그의 내용을 캡슐화합니다. Fault 객체에는 다음과 같은 어트리뷰트가 있습니다:

faultCode

An int indicating the fault type.

faultString

결함과 연관된 진단 메시지가 포함된 문자열.

다음 예제에서는 복소수 형의 객체를 반환하여 의도적으로 Fault를 발생시킵니다. 서버 코드:

from xmlrpc.server import SimpleXMLRPCServer

# A marshalling error is going to occur because we're returning a
# complex number
def add(x, y):
    return x+y+0j

server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(add, 'add')

server.serve_forever()

이전 서버에 대한 클라이언트 코드:

import xmlrpc.client

proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
try:
    proxy.add(2, 5)
except xmlrpc.client.Fault as err:
    print("A fault occurred")
    print("Fault code: %d" % err.faultCode)
    print("Fault string: %s" % err.faultString)

ProtocolError 객체

class xmlrpc.client.ProtocolError

ProtocolError 객체는 하부 전송 계층에서의 프로토콜 에러를 기술합니다 (가령 URI로 명명된 서버가 없을 때 404 ‘not found’ 에러). 다음과 같은 어트리뷰트가 있습니다:

url

에러를 일으킨 URI나 URL.

errcode

에러 코드.

errmsg

에러 메시지나 진단 문자열.

headers

에러를 일으킨 HTTP/HTTPS 요청의 헤더를 포함하는 딕셔너리.

다음 예에서는 잘못된 URI를 제공하여 의도적으로 ProtocolError를 발생시킵니다:

import xmlrpc.client

# create a ServerProxy with a URI that doesn't respond to XMLRPC requests
proxy = xmlrpc.client.ServerProxy("http://google.com/")

try:
    proxy.some_method()
except xmlrpc.client.ProtocolError as err:
    print("A protocol error occurred")
    print("URL: %s" % err.url)
    print("HTTP/HTTPS headers: %s" % err.headers)
    print("Error code: %d" % err.errcode)
    print("Error message: %s" % err.errmsg)

MultiCall 객체

MultiCall 객체는 원격 서버에 대한 여러 호출을 단일 요청으로 캡슐화하는 방법을 제공합니다 1.

class xmlrpc.client.MultiCall(server)

boxcar 메서드 호출에 사용되는 객체를 만듭니다. server는 최종 호출 대상입니다. 결과 객체를 호출할 수 있지만, 즉시 None을 반환하고, 호출 이름과 매개 변수를 MultiCall 객체에 저장하기만 합니다. 객체 자체를 호출하면 저장된 모든 호출이 단일 system.multicall 요청으로 전송됩니다. 이 호출의 결과는 제너레이터입니다; 이 제너레이터를 이터레이트 하면 개별 결과를 산출합니다.

이 클래스의 사용 예는 다음과 같습니다. 서버 코드:

from xmlrpc.server import SimpleXMLRPCServer

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

def subtract(x, y):
    return x - y

def multiply(x, y):
    return x * y

def divide(x, y):
    return x // y

# A simple server with simple arithmetic functions
server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_multicall_functions()
server.register_function(add, 'add')
server.register_function(subtract, 'subtract')
server.register_function(multiply, 'multiply')
server.register_function(divide, 'divide')
server.serve_forever()

이전 서버에 대한 클라이언트 코드:

import xmlrpc.client

proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
multicall = xmlrpc.client.MultiCall(proxy)
multicall.add(7, 3)
multicall.subtract(7, 3)
multicall.multiply(7, 3)
multicall.divide(7, 3)
result = multicall()

print("7+3=%d, 7-3=%d, 7*3=%d, 7//3=%d" % tuple(result))

편의 함수

xmlrpc.client.dumps(params, methodname=None, methodresponse=None, encoding=None, allow_none=False)

params를 XML-RPC 요청으로, 또는 methodresponse가 참이면 응답으로 변환합니다. params는 인자의 튜플이거나 Fault 예외 클래스의 인스턴스일 수 있습니다. methodresponse가 참이면, 단일 값만 반환될 수 있는데, params의 길이가 1이어야 한다는 뜻입니다. 제공되면, encoding은 생성된 XML에서 사용할 인코딩입니다; 기본값은 UTF-8입니다. 파이썬의 None 값은 표준 XML-RPC에서 사용할 수 없습니다; 확장을 통해 이를 사용하려면 allow_none에 참값을 제공하십시오.

xmlrpc.client.loads(data, use_datetime=False, use_builtin_types=False)

XML-RPC 요청이나 응답을 파이썬 객체 (params, methodname)로 변환합니다. params는 인자의 튜플입니다; methodname은 문자열이거나 패킷에 메서드 이름이 없으면 None입니다. XML-RPC 패킷이 결함 조건을 나타내면, 이 함수는 Fault 예외를 발생시킵니다. use_builtin_types 플래그를 사용하여 날짜/시간 값을 datetime.datetime 객체로 표현하고 바이너리 데이터를 bytes 객체로 표현할 수 있습니다; 이 플래그는 기본적으로 거짓입니다.

사용되지 않는 use_datetime 플래그는 use_builtin_types와 유사하지만, 날짜/시간 값에만 적용됩니다.

버전 3.3에서 변경: use_builtin_types 플래그가 추가되었습니다.

클라이언트 사용 예

# simple test program (from the XML-RPC specification)
from xmlrpc.client import ServerProxy, Error

# server = ServerProxy("http://localhost:8000") # local server
with ServerProxy("http://betty.userland.com") as proxy:

    print(proxy)

    try:
        print(proxy.examples.getStateName(41))
    except Error as v:
        print("ERROR", v)

HTTP 프락시를 통해 XML-RPC 서버에 액세스하려면, 사용자 정의 트랜스포트를 정의해야 합니다. 다음 예제는 방법을 보여줍니다:

import http.client
import xmlrpc.client

class ProxiedTransport(xmlrpc.client.Transport):

    def set_proxy(self, host, port=None, headers=None):
        self.proxy = host, port
        self.proxy_headers = headers

    def make_connection(self, host):
        connection = http.client.HTTPConnection(*self.proxy)
        connection.set_tunnel(host, headers=self.proxy_headers)
        self._connection = host, connection
        return connection

transport = ProxiedTransport()
transport.set_proxy('proxy-server', 8080)
server = xmlrpc.client.ServerProxy('http://betty.userland.com', transport=transport)
print(server.examples.getStateName(41))

클라이언트와 서버 사용 예

SimpleXMLRPCServer 예제를 참조하십시오.

각주

1

이 접근법은 xmlrpc.com에서의 토론에서 처음 제시되었습니다.