본문 바로가기

학습컨텐츠

웹 서비스(Web Service)


이 컨텐츠는 지난 2006년 겨울캠프에서 사용된 학습자료입니다.


 

HTTP의 이해

이 수업의 주제인 웹 서비스를 이해하려면, HTTP프로토콜에 대한 기본적인 이해가 필수적이다.

인터넷 주소에 항상 붙어다니는 "http://"는 홈페이지의 정보가 HTTP라고 하는 규칙을 이용하여 전송됨을 의미한다. HTTP(HyperText Transfer Protocol)는 WWW(World Wide Web)을 통해 정보를 주고받기 위한 프로토콜이다.

HTTP는 Request(요청)와 Response(응답)의 두 메시지를 사용한다. 클라이언트의 Request요청을 받은 서버는 상응하는 Response 메시지를 클라이언트에게 보내주고 연결을 종료한다.

HTTP의 각 메시지는 한 개의 비어있는 라인으로 구분된 Header와 Body 두 부분으로 구성된다. Request 메시지의 헤더 제일 첫 줄에는 요청 방식(Request Method) 과 요청 URI (Request-URI)와 HTTP버전으로 이루어진 Request-Line이 있어야 하고, 다음 줄에는 접속하고 있는 Host의 정보가, 그 다음 줄부터는 클라이언트의 부수적인 정보(사용중인 플랫폼과 브라우저의 정보, 수신할 수 있는 언어의 인코딩 등)가 주어진다.

<request-line>
<headers>
<blank line>
[<request-body>]

예를 들어, 웹 브라우저의 주소창에 카이스트 과학영재교육연구원 홈페이지 자유게시판의 주소를 입력하고 엔터를 치면 브라우저는 talent.kaist.ac.kr서버의 80번 포트로 다음 내용을 전송한다.


GET /bbs/zboard.php?id=board_free HTTP/1.1
Host: talent.kaist.ac.kr
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ko) Firefox/2.0
 

이 메시지는 HTTP/1.1의 GET 방식으로 서버의 /bbs/zboard.php?id=board_free에 해당하는 URI를 호출하였음을 뜻한다. 또한 사용자가 Windows XP에서 Firefox 2.0 브라우저를 사용하고 있다는 것도 확인할 수 있다. 데이터를 요청하기만 하는 GET방식 메시지의 경우 Body가 필요 없다. 다른 방식인 POST 방식은 부가적인 데이터를 <request-body>에 포함하는데, HTTP의 요청 방식에 대한 더 자세한 내용은 학습방의 자료를 참고하기 바란다.

HTTP 응답의 Header에는 한 줄의 상태 라인과 서버의 정보, 전송될 데이터의 크기와 형식 등이 주어지고, Body에는 요청한 데이터가 포함된다. 이 데이터는 HTML문서일 수도 있고, 이미지나 한글 문서 파일일 수도 있다.

<status-line>
<headers>
<blank line>
[<response-body>]


앞서 예로 들었던 카이스트 과학영재교육원 자유게시판의 요청에 대한 서버의 Response 메시지는 아래와 같다.

HTTP/1.1 200 OK
Server: Apache/1.3.27 (UNIX) PHP/4.2.3
Date: Sun, 31 Dec 2006 16:34:06 GMT
Content-Length: 48535
Content-Type: text/html

<html>
<head> 
    <title>KAIST과학영재교육연구원</title> 
    <meta http-equiv=Content-Type content=text/html; charset=EUC-KR>
...

첫 줄은 응답의 종류를 말해준다. HTTP/1.1은 이 메시지가 HTTP/1.1 규약을 이용한다는 것을 뜻하고, "200 OK"는 서버의 응답에 대한 상태 코드(Status-Code)로, 요청된 데이터에 해당하는 정보가 포함되었음을 뜻한다. 다른 상태 코드나 HTTP에 대한 더 자세한 사항은 RFC 문서 2616을 참고하기 바란다.

웹 서비스는 HTTP를 통해 컴퓨터 사이에서 이루어지는 일종의 서비스이다. 다음으로는 웹 서비스가 어떤 것인지, 그 예로는 무엇이 있는지 알아보기로 한다.



웹 서비스란?

 

W3C(World Wide Web Consortium)에서는 다음과 같이 웹 서비스를 정의한다.

a software system designed to support interoperable machine-to-machine interaction over a network
네트워크상에서 서로 다른 종류의 컴퓨터들 간에 상호작용을 하기 위한 소프트웨어 시스템


이 정의는 인터넷을 이용하는 다양한 프로그램들 전체를 포함하지만, 대부분의 경우 "웹 서비스"란 용어는 인터넷과 같은 네트워크를 통하여 이용할 수 있는 API(Application Programming Interface), 그 중에서도 XML 등을 이용하여 플랫폼과 언어에 독립적으로 수행할 수 있는 시스템을 의미한다.

웹 서비스가 어떤 것인지 예를 보면서 알아보자.




웹 서비스의 예

 

● 네이버 OpenAPI



네이버는 지난 3월 OpenAPI서비스를 시작했다. 검색결과 제공 서비스를 시작으로, 8월에는 네이버 지도를 사용자의 홈페이지에 삽입하고 임의로 꾸밀 수 있도록 네이버 지도 API를 공개했다. 예를 들어, "KAIST"로 검색한 결과를 얻고 싶으면 다음 주소로 HTTP요청을 보내면 RSS형식으로 포맷된 결과를 받을 수 있다.

http://openapi.naver.com/search?query=KAIST&display=10&start=1&target=webkr 

네이버 지도 API에서는 네이버 지도 컴포넌트를 사용자가 자바스크립트를 이용하여 사용할 수 있게 해 준다. 네이버 오픈API를 사용한 많은 프로그램이 개발되었다. 네이버 책 검색을 이용하여 원하는 책 정보를 블로그에 입력해주는 태터툴즈 플러그인이나, 네이버 지도와 구글 위성사진을 한번에 볼 수 있는 사이트(NGMap)가 그 예이다.

구글 API



 

웹 2.0의 선두주자로 손꼽히는 구글은 다양한 웹 서비스를 제공한다. 구글의 웹 서비스를 이용하면 구글 지도와 구글 어스, 구글 검색결과를 웹 사이트에 활용할 수 있고, 개인화된 구글 홈페이지의 모듈, 구글 데스크탑의 가젯 등을 개발할 수도 있다.

다음 장에서는 웹 서비스를 실제로 구현하는 방법 중 하나인 XML-RPC에 대해 알아보자.
 


XML-RPC


 

RPC와 XML-RPC

RPC(Remote Procedure Call)는 다른 컴퓨터에 있는 프로시저를 호출하는 기능을 말한다. 이 개념은 분산 처리에서 중요한 개념으로 자주 도입된다. 작업을 여러 개의 작은 단위로 나누어서 여러 컴퓨터에서 동시에 수행하게 한다면 실행의 효율이 증가할 수 있을 것이다. 또한, 웹 서비스에 있어서 서비스 이용자는 서비스 제공자에게 RPC요청을 함으로써 원하는 정보를 제공받을 수 있다.

RPC는 서로 다른 기종(운영체제, 프로그래밍 언어, 인코딩 등)간에서 이루어질 수 있기 때문에, 파라미터의 전송 방법에 좀더 일반화된 형태가 필요하다. XML-RPC는 인수나 계산 결과를 주고받기 위해 XML을 사용한다. XML은 문서 교환 형식의 표준으로 이미 자리를 잡았기 때문에, XML-RPC는 플랫폼에 독립적으로 수행될 수 있다.

XML-RPC는 HTTP를 이용한다. 따라서 HTTP의 단점도 그대로 상속받는다. 우선 상태가 유지되지 않는다. 연속으로 두 번 함수를 호출할 때 서버에서는 이 두 함수 요구를 완전히 별개의 요구로 받아들인다. 즉 이전 함수 호출에서 어떤 객체를 생성했다고 해도 그 다음 호출에서 그 객체를 사용할 수 없게 된다. 또한 HTTP를 함수 호출에 이용함으로써 생기는 보안 문제도 논쟁거리이고, 인증을 기본적으로 지원해주지 않는 것도 불편한 일이다.

많은 서버를 이용하는 대형 작업이나, 극도의 보안이 요구되는 작업에는 XML-RPC가 적합하지 않지만, XML-RPC를 이용하면 쉽게 신뢰할 만한 기능을 구현할 수 있다. 쉽게 사용할 수 있고 원하는 기능을 빨리 구현할 수 있다는 것이 XML-RPC의 장점이다.

XML-RPC는 Python을 포함하여 Java, Perl, Tcl, COM, PHP, ASP, C/C++ 등 다양한 언어로 구현되어 있고, Python 2.2부터는 XML-RPC가 파이썬 표준 모듈로 포함되어 있다. 이처럼 XML-RPC는 거의 모든 컴퓨팅 환경에서 손쉽게 사용할 수 있다.


 

XML-RPC 프로토콜

XML-RPC의 처리 과정을 살펴보자. 로컬 컴퓨터에서 몇 개의 인수를 가지고 원격의 함수를 호출한다. XML-RPC 클라이언트는 함수의 이름과 인수를 XML 형식으로 변환(Marshalling)하고 HTTP 프로토콜을 이용하여 서버 측에 요구 (Request) 메시지를 보낸다. XML-RPC 서버는 XML로 전달된 함수 이름과 인수를 언어에 맞는 자료형으로 변환(Unmarchalling)하고 실제 함수를 호출한다. 함수가 리턴한 결과는 다시 XML 문서로 변환(Marshalling)되어 클라이언트로 전송되고, 클라이언트는 이것을 해석해서 언어에 맞는 객체로 변환하여 함수의 호출원으로 전달한다.


 

betty.userland.com서버로 examples.getStateName(41)이란 함수를 호출한다고 하자. 클라이언트에서 서버로 보내는 HTTP Request는 아래와 같다.

POST /RPC2 HTTP/1.0
Host: betty.userland.com
User-Agent: xmlrpclib.py/1.0.1 (by www.pythonware.com)
Content-Type: text/xml
Content-Length: 184

<?xml version='1.0'?>
<methodCall>
<methodName>examples.getStateName</methodName>
<params>
<param>
<value><i4>41</i4></value>
</param>
</params>
</methodCall>


XML-RPC요청은 POST방식이어야 한다. 이는 HTTP Request의 Body로 XML 문서가 전송되어야 하기 때문이다. 헤더의 Content-Type은 text/xml이어야 한다.

XML-RPC에서는 다양한 형태의 변수를 전달하기 위해 통일된 스펙을 사용한다. XML-RPC의 공식 홈페이지의 http://www.xmlrpc.com/spec에서 확인할 수 있다. XML 본문은 최상위 엘리먼트인 <methodCall>로 이루어지고, 그 안에 메쏘드의 이름을 텍스트로 갖는 <methodName>과 생략 가능한 <params> 엘리먼트를 하나씩 갖는다. <params> 엘리먼트의 아래에는 하나 이상의 <param> 엘리먼트가 있고, 각 <param>은 하나의 <value> 엘리먼트를 가진다.


<value> 엘리먼트는 함수의 인수 데이터를 포함하는 것으로 숫자, 문자열, 배열 등 다양한 형식이 될 수 있으며 그 종류는 다음 표와 같다.

종류

예시

설명

boolean

<boolean>1</boolean>

0(거짓) 또는 1(참)

double

<double>-3.14</double>

배정도 실수형

int

<int>13</int> 또는 <i4>13</i4>

정수값

string

<string>hello world!</string>

문자열

dateTime.iso8601

<dateTime.iso8601>
19980717T14:08:55
</dateTime.iso8601>

날짜와 시간

array

<array><data>
<value><i4>1404</i4></value>

<value><string>hi</string></value>

<value><i4>1</i4></value>

</data></array>

key를 가지지 않는

value들의 배열

struct

<struct>
<member>
<name>foo</name>
<value><i4>1</i4></value>

</member>
<member>
<name>bar</name>
<value><i4>2</i4></value>

</member>
</struct>

key를 가지는

value들의 배열

XML-RPC 응답의 메시지는 정상적인 응답을 하는 경우와 오류가 발생한 경우의 응답 두 가지가 있다. 두 경우 모두 <methodResponse>를 최상위 엘리먼트로 하며, 정상적인 응답을 하는 경우는 <params>, <param>, <value>가 한 개씩 있는 구조를 가지고, 비정상적인 응답을 하는 경우에는 <falut> 엘리먼트와 그 아래에 faultCode와 faultString을 담은 <struct>가 포함된다.

다음 두 예는 각각 정상적인 응답을 할 때와 오류가 발생한 경우의 응답 메시지이다.


HTTP/1.1 200 OK
Connection: close
Content-Length: 141
Content-Type: text/xml
Date: Sun, 31 Dec 2006 14:48:35 GMT
Server: UserLand Frontier/9.5-WinNT

<?xml version="1.0"?>
<methodResponse>
    <params>
        <param>
            <value><string>South Dakota</string></value>
        </param>
    </params>
</methodResponse>
 
HTTP/1.1 200 OK
Connection: close
Content-Length: 426
Content-Type: text/xml
Date: Sun, 31 Dec 2006 14:48:35 GMT
Server: UserLand Frontier/9.5-WinNT

<?xml version="1.0"?>
<methodResponse>
    <fault>
        <value>
            <struct>
                <member>
                    <name>faultCode</name>
                    <value><int>4</int></value>
                </member>
                <member>
                    <name>faultString</name>
                    <value><string>Too many parameters.</string></value>
                </member>
            </struct>
        </value>
    </fault>
</methodResponse>



 

Python과 XML-RPC

Python에서 XML-RPC의 클라이언트 기능을 이용하는 것은 놀랄 만큼 쉽다. xmlrpclib라는 라이브러리에서 XML-RPC의 모든 기능을 지원하기 때문에, 클라이언트에서는 보통의 함수를 호출하듯이 XML-RPC를 사용할 수 있다. http://betty.userland.com에서 제공하고 있는 examples모듈의 getStateName()함수를 이용하여 미국의 ABC순 41번째 주의 이름을 알아오려면 아래와 같이 하면 된다.

from xmlrpclib import ServerProxy
betty=ServerProxy("
http://betty.userland.com/")
betty.examples.getStateName(41)

파이썬 객체를 XML형식으로 변환하는 것을 마샬링(Marshalling)이라고 하고, 반대로 XML로 표현된 객체를 파이썬 객체로 변환하는 것을 언마샬링(Unmarshalling)이라고 한다. xmlrpclib에서는 마샬링와 언마샬링을 위한 함수로 dumps와 load를 지원한다.

다음과 같이 명령어를 입력하고 결과를 보면서 실습해 보자.

import xmlrpclib
xmlp=xmlrpclib.dumps((1,'abc',[10,20]),'function')
print xmlp
xmlrpclib.loads(xmlp)

xmlrpclib의 기작에 대해서 더 알아보고 싶다면 python 설치폴더 아래 Lib\xmlrpclib.py를 분석해보길 바란다.


 

Python에서 XML-RPC서버 구현하기

Python에서 제공하는 라이브러리를 이용하면 XML-RPC 서버도 쉽게 만들 수 있다. SimpleXMLRPCServer 모듈은 SimpleXMLRPCServer와 SimpleXMLRPCRequestHandler 클래스를 지원한다. SimpleXMLRPCServer는 Socket.TCPServer의 서브클래스로 XML-RPC 소켓 서버를 만드는 데 사용된다. SimpleXMLRPCRequestHandler는 SimpleXMLRPCServer클래스가 이용하는 리퀘스트 핸들러 클래스로,

다음은 간단한 XML-RPC서버이다. 이 서버는 정수 값을 받아서 두 배의 값을 리턴하는 double 함수를 제공한다.

from SimpleXMLRPCServer import *

class MyRequestHandler(SimpleXMLRPCRequestHandler):
def _dispatch(self, method, params):
try:
    server_method=getattr(self, "do_"+method)
except:
    raise AttributeError, "No XML-RPC procedure do_%s" % method
return server_method(*params)

def log_message(self, format, *args):
    print format % args


def do_double(self, k):
    return k*2

if __name__=='__main__':
    server = SimpleXMLRPCServer(('',8000), MyRequestHandler)
    server.serve_forever()

클라이언트에서 함수 호출을 받은 SimpleXMLRPCServer는 연결된 리퀘스트 핸들러의 _dispatch 메쏘드를 호출한다. 이 때 전달되는 두 인수는 호출 함수의 이름(문자열)과 전달될 인수들의 튜플이다. _dispatch 메쏘드에서는 getattr을 사용하여 해당하는 함수를 호출하고, 만일 그러한 함수가 존재하지 않으면 AttributeError를 발생시킨다. "double"함수를 요청받았으므로, "do_double"함수를 찾아서 그 결과를 클라이언트에게 돌려준다.




다른 프로토콜의 예


JSON-RPC

JSON-RPC는 JSON이라는 인코딩 방식을 이용하는 RPC프로토콜이며, 역시 다양한 언어로 만들어진 라이브러리들을 이용하여 쉽게 사용할 수 있다. '<', '>'를 이용하는 XML과 다르게 JSON은 '{', '}'를 이용하여 데이터를 구성하며, XML보다 조금 더 길이가 짧다는 이점이 있다. XML과 JSON을 비교해 보자.


<classinfo>
    <students>
        <student>
            <name>Michael Smith</name>
            <average>99.5</average>
            <age>17</age>
            <graduating>true</graduating>
        </student>
        <student>
            <name>SteveJohnson</name>
            <average>34.87</average>
            <age>17</age>
        </student>
    </students>
</classinfo>

{ "classinfo" :
    {
        "students" : [
            {
                "name" : "Michael Smith",
                "average" : 99.5,
                "age" : 17,
                "graduating" : true
            },
            {
                "name" : "Steve Johnson",
                "average" : 34.87,
                "age" : 17,
                "graduating" : false
            }
        ]
    }
}


 

SOAP

SOAP(Simple Object Access Protocol)은 XML-RPC에서 시작하여 이름 공간(namespace)개념을 추가하고 여러 기능을 확장한 프로토콜이다. 더 자세한 설명은 이 교재의 범위를 벗어나므로 생략하고, SOAP 메시지의 간단한 예를 보자. 4.5와 5.4를 더하는 함수 add를 호출하는 SOAP 메시지의 예이다.


<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<w:add xmlns:w="http://www.examples.com/services/math">
<w:op1>4.5</w:op1>
<w:op2>5.4</w:op2>
</w:add>
</soap:Body>
</soap:Envelope>