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입니다. 선택적 네 번째 인자는 디버깅 플래그입니다.

그 뒤에 오는 매개 변수들은 반환된 프락시 인스턴스 사용을 제어합니다. allow_none이 참이면, 파이썬 상수 None이 XML로 변환됩니다; 기본 동작은 NoneTypeError를 발생시키는 것입니다. 이것은 XML-RPC 명세에 일반적으로 사용되는 확장이지만, 모든 클라이언트와 서버에서 지원되는 것은 아닙니다; 설명은 http://ontosys.com/xml-rpc/extensions.php를 참조하십시오. use_builtin_types 플래그를 사용하여 날짜/시간 값을 datetime.datetime 객체로 표현하고 바이너리 데이터를 bytes 객체로 표현할 수 있습니다; 이 플래그는 기본적으로 거짓입니다. datetime.datetime, bytesbytearray 객체는 호출로 전달될 수 있습니다. headers 매개 변수는 각 요청과 함께 보낼 선택적 HTTP 헤더의 시퀀스이며, 헤더 이름과 값을 나타내는 2-튜플의 시퀀스로 표현됩니다. (예를 들어 [(‘Header-Name’, ‘value’)]). 사용되지 않는 use_datetime 플래그는 use_builtin_types와 유사하지만, 날짜/시간 값에만 적용됩니다.

버전 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에서 변경: 접두사가 있는 형 태그 지원이 추가되었습니다 (예를 들어 ex:nil). 숫자를 위해 Apache XML-RPC 구현이 사용하는 추가 형의 역마샬링 지원이 추가되었습니다: i1, i2, i8, biginteger, floatbigdecimal. 설명은 http://ws.apache.org/xmlrpc/types.html 을 참조하십시오.

더 보기

XML-RPC HOWTO

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

XML-RPC Introspection

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

XML-RPC Specification

공식 명세.

Unofficial XML-RPC Errata

Fredrik Lundh의 “비공식 정오표, XML-RPC 명세의 특정 세부 사항을 명확하게 설명할 뿐만 아니라 여러분 자신의 XML-RPC 구현을 설계할 때 사용할 ‘모범 사례’에 대한 힌트를 제공하기 위한 것입니다.”

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

결함 형을 나타내는 문자열.

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에서의 토론에서 처음 제시되었습니다.