<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule"
>

<channel>
	<title>EMSTONE Bebop &#187; ONVIF</title>
	<atom:link href="http://bebop.emstone.com/tags/onvif/feed/" rel="self" type="application/rss+xml" />
	<link>http://bebop.emstone.com</link>
	<description>엠스톤 개발팀 블로그</description>
	<lastBuildDate>Sun, 29 Jan 2012 05:25:29 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/2.0/kr/</creativeCommons:license>
		<item>
		<title>ONVIF 장치 검색 (Device Discovery)</title>
		<link>http://bebop.emstone.com/2009/10/13/onvif-device-discovery/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=onvif-device-discovery</link>
		<comments>http://bebop.emstone.com/2009/10/13/onvif-device-discovery/#comments</comments>
		<pubDate>Mon, 12 Oct 2009 23:54:53 +0000</pubDate>
		<dc:creator>moonpfe</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[ONVIF]]></category>

		<guid isPermaLink="false">http://bebop.emstone.com/?p=856</guid>
		<description><![CDATA[ONVIF  에서는 WS-Discovery (Web Services Dynamic Discovery)  표준을 기반으로 한 장치 검색 (Device Discovery)  웹 서비스를 사용합니다.  WS-Discovery 표준의 특정 부분을 확장하거나 제약하여 사용하기 때문에 WS-Discovery 와 완벽하게 호환되지는 않습니다. NVC 는 장치 검색을 통해 사용 가능한 NVT 를 검색합니다. &#8230; <a href="http://bebop.emstone.com/2009/10/13/onvif-device-discovery/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>ONVIF  에서는 WS-Discovery (Web Services Dynamic Discovery)  표준을 기반으로 한 장치 검색 (Device Discovery)  웹 서비스를 사용합니다.  WS-Discovery 표준의 특정 부분을 확장하거나 제약하여 사용하기 때문에 WS-Discovery 와 완벽하게 호환되지는 않습니다.</p>
<p>NVC 는 장치 검색을 통해 사용 가능한 NVT 를 검색합니다. NVT (Network Video Transmitter) 는 WS-Discovery 의 Target Service 역할에 해당하고, NVC (Network Video Client) 는 WS-Discovery 의 Client 역할에 해당합니다. 장치 검색에서는  Ws-Discovery 의 DP (Discover Proxy) 를 확장하여 보다 복합한 네트워크 상황도 처리할 수 있습니다.  WS-Discovery 와는 달리 NVC/NVT 는 DP 역할은 하지 않습니다.  endpoint reference 에 URN:UUID 를 사용합니다.</p>
<p>NVT  동작 모드</p>
<ul>
<li> Discoverable &#8211; 기본 모드로 일반적인 Target Service 처럼 동작합니다. 네트워크에 참여하거나 메타 데이터 변경 시 메시지를 보내며, Probe 와 Resolve 메시지를 Listen 하고, 그에 대한 응답을 보냅니다.</li>
<li>Non-discoverable &#8211; 메시지를 Listen 하지 않습니다. (DOS 공격 대비)</li>
</ul>
<p>메시지 교환</p>
<div id="attachment_858" class="wp-caption aligncenter" style="width: 430px"><a href="http://bebop.emstone.com/wp-content/uploads/2009/10/model.png" rel="lightbox[856]"><img class="size-full wp-image-858" src="http://bebop.emstone.com/wp-content/uploads/2009/10/model.png" alt="The message exchanges between a Target Service and a Client" width="420" height="428" /></a><p class="wp-caption-text">The message exchanges between a Target Service and a Client</p></div>
<p>메시지 종류</p>
<ul>
<li>HELLO : 단방향 메시지로, Target Service 가 네트워크에 참여하거나 메타 데이터를 변경했을 경우에 보낸다.</li>
<li>Bye : 단방향 메시지로 Target Service 가 해당 네트워크에서 떠날 때 보낸다.</li>
<li>Probe : Client 가 Type 과 Scope 에 해당하는 Target Service 를 찾을 때 사용한다.</li>
<li>Probe Match : Probe 메시지에 대한 Target Service 의 응답</li>
<li>Resolve : Client 가 이름으로 Target Service 를 찾을 때 사용한다.</li>
<li>Resolve Match : Resolve 메시지에 대한 Target Service 의 응답</li>
</ul>
<p>장치 검색에서는 보두 복잡한 네트워크 환경에서도 동작할 수 있도록 하기 위해 WS-Discovery  의 Discovery Proxy(DP) 를 확장하여 사용합니다. WS-Discovery 에서 NVC 와 NVT 가 같은 네트워크 도메인에 존재하지 않으면,  NVC가 멀티 캐스트 Probe 메시지를 통해 NVT 를 찾을 수 없습니다. 장치 검색의 DP 는 다음과 같은 네트워크 상황에서도 검색을 지원합니다.</p>
<ul>
<li>NVT 는 private 네트워크에 존재하고, NVC 는 public 네트워크에 존재하는 경우</li>
<li>NVT 는 public 네트워크에 존재하고, NVC 는 private 네트워크에 존재하는 경우</li>
<li>NVT 는 특정 private 네트워크에 존재하고, NVC 는 그와 다른 private 네트워크에 존재하는 경우</li>
<li>NVT 와 NVC 둘다 public 네트워크에 존재하는 경우</li>
</ul>
<pre>  Endpoint reference
    [address] : URN:UUID 형식을 사용
    [reference properties] : IPv4/v6 addresses

  SOAP binding for endpoint references
    [address] : SOAP 메시지의 [destination] header field
    [reference property/parameter] : SOAP 메시지의 header block

  Service addresses
    HELLO 메시지 안의 &lt;d:Xaddrs&gt; 엘리먼트가 NVT 장치의 서비스 주소를 나타냄
    NVT 는 80 번 포트 장치 서비스 엔트리를 제공해야 한다.

  HELLO
    Types
      NVT는 &lt;d:Types&gt; 에 dn:NetworkVideoTransmitter 이 있어야 한다.
    Scope
      [scheme]://authority/&lt;path&gt;
        ex) onvif://www.onvif.org/&lt;path&gt;

      type/video_encoder
      type/ptz
      type/audio_encoder
      type/video_analytics
      location
      hardware
      name

  Probe/Probe Match
    NVT 는 Probe Match 메시지에 해당하는 장치 서비스에 대한 &lt;d:Xaddrs&gt; 엘리먼트를
    포함하고 있어야 한다. 대체로 &lt;d:Xaddrs&gt; 엘리먼트는 해당 서비스에 대한 관리와
    설정에 대한 하나의 주소만을 가지고 있다고 한다.

  Resolve/Resolve Match
    대부분 Resolve 와 Resolve Match 메시지 교환을 불필요하다고 한다. 하지만
    [WS-Discovery] 와의 호환을 위해서는 resolve match response 를 구현해야
    한다고 한다.

  Bye
    네트워크에서 나갈 때 보내는 단방향 메시지

  SOAP Fault Messages
    멀티 캐스트에 대해서는 무시한다.
    유니 캐스트에 대해서는 에러 발생 시 SOAP Fault Message 를 보낸다.

  멀티 캐스트 메시지
     DISCOVERY_PORT : port 3702 [IANA]
     IPv4 multicast address: 239.255.255.250
     IPv6 multicast address: FF02::C (link-local scope)
     메시지는 SOAP over UDP 를 사용하여 보낸다.
</pre>
<pre>Discovery Proxy 가 없을 경우 메시지 교환 시나리오 (예상)

NVT
  HELLO
      src : UDP/[Local Port]
      dst : Multicast UDP/3702

NVC
  Probe
      src : UDP/[Local Port]
      dst : Multicast UDP/3702

NVT
  Probe Match
      src : UDP/3702
      dst : Client UDP/[Client Port]

NVC
  GetXXX
      src : HTTP/[Local Port]
      dst: HTTP/80

NVT
  GetXXXResponse (metadata)
      src : HTTP/80
      dst: Client HTTP/[Client Port]

NVT
  Bye
      src : UDP/[Local Port]
      dst : Multicast UDP/3702</pre>
]]></content:encoded>
			<wfw:commentRss>http://bebop.emstone.com/2009/10/13/onvif-device-discovery/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/2.0/kr/</creativeCommons:license>
	</item>
		<item>
		<title>SOAP 라이브러리 기술 조사</title>
		<link>http://bebop.emstone.com/2009/07/28/soap-library-survey/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=soap-library-survey</link>
		<comments>http://bebop.emstone.com/2009/07/28/soap-library-survey/#comments</comments>
		<pubDate>Tue, 28 Jul 2009 10:12:50 +0000</pubDate>
		<dc:creator>keedi</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[csoap]]></category>
		<category><![CDATA[gsoap]]></category>
		<category><![CDATA[libsooup]]></category>
		<category><![CDATA[ONVIF]]></category>
		<category><![CDATA[SOAP]]></category>
		<category><![CDATA[SOAP::Simple]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[       주의 : [SOAP 라이브러리 기술 조사]의 가장 최근 판은  이곳 에서 확인할 수 있습니다.

 시작하며

 ONVIF  명세를 지원하는 IP 카메라의 경우  SOAP  방식의 웹서비스를 기반으로 카메라를 제어하는 기능을 제공합니다. 기존의  IP 카메라 가 자체적인 프로토콜을 정의하고 제조사가 제공하는 라이브러리를 이용해야지만 카메라에 접근해서 조작할 수 있었습니다. 이 경우 카메라 서비스의 접근성은 무척 떨어지는데 대표적으로 제조사가 윈도우즈 라이브러리만 제공할 경우 정상적인 방법으로는 타 운영체제에서 카메라를 제어할 수 없...
     <a href="http://bebop.emstone.com/2009/07/28/soap-library-survey/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><strong>주의</strong>: [SOAP 라이브러리 기술 조사]의 가장 최근 판은 <a href="http://bebop.emstone.com/~keedi/timetolog/id/26">이곳</a>에서 확인할 수 있습니다.</p>
<h3>시작하며</h3>
<p><a href="http://www.onvif.org">ONVIF</a> 명세를 지원하는 IP 카메라의 경우 <a href="http://www.w3.org/TR/soap">SOAP</a> 방식의 웹서비스를<br />
기반으로 카메라를 제어하는 기능을 제공합니다.<br />
기존의 <a href="http://en.wikipedia.org/wiki/IP_camera">IP 카메라</a>가 자체적인 프로토콜을 정의하고 제조사가 제공하는<br />
라이브러리를 이용해야지만 카메라에 접근해서 조작할 수 있었습니다.<br />
이 경우 카메라 서비스의 접근성은 무척 떨어지는데 대표적으로<br />
제조사가 윈도우즈 라이브러리만 제공할 경우 정상적인 방법으로는<br />
타 운영체제에서 카메라를 제어할 수 없는 상황이 발생하기도 합니다.<br />
이와 비교해 표준적인 웹서비스인 SOAP 방식을 지원하는<br />
ONVIF IP 카메라의 경우 프로그래밍 언어와 운영체제 심지어 하드웨어의 특성을<br />
뛰어 넘어 제품을 제어할 수 있다는 측면에서 큰 장점을 가집니다.<br />
단지 HTTP 프로토콜 통신을 지원하고 XML 로 구성된 SOAP 메시지를<br />
파싱할 수 있고 ONVIF 카메라가 정의한 명세만 이해할 수 있으면<br />
어떠한 환경에서도 카메라가 제공하는 서비스를 받을 수 있습니다.</p>
<p>이런 웹서비스는 컴퓨터간 통신을 가능하게 하고 서비스와 자료를<br />
교환할 수 있게 해주는 것에 대한 모든 것을 의미합니다.<br />
웹이 그러하듯이 웹서비스는 개방된 표준을 사용해서<br />
응용을 더 편리하고 표준적인 방법으로 사용할 수 있게 도와줍니다.<br />
SOAP 이란 Simple Object Access Protocol 의 약자로<br />
<a href="http://www.w3.org">W3C</a> 가 설계한 표준으로 웹서비스의 가장 기본이 되는 부분입니다.<br />
SOAP 명세는 데이터를 어떻게 표현할지와 통신에 무엇이 필요한지,<br />
통신 계층에서 메시지를 어떻게 연결할 것인지를 포함합니다.<br />
문서에서는 C 언어에서 사용 가능한 SOAP 라이브러리에 대해<br />
알아보고 특징과 장단점을 정리합니다.</p>
<h3>SOAP 의 장단점</h3>
<h4>장점</h4>
<ul>
<li>SOAP 에서 표준 전송 프로토콜로 사용하는 HTTP 는 기존 원격 기술들에 비해서 프록시와 방화벽에 구애받지 않고 쉽게 통신 가능</li>
<li>다른 전송 프로토콜 사용을 허용하므로 표준인 HTTP 외에도 SMTP, FTP 등을 사용 가능</li>
<li>플랫폼 독립적</li>
<li>프로그래밍 언어에 독립적</li>
<li>간단(CORBA 에 비해 상대적으로)하고, 확장 가능</li>
</ul>
<h4>단점</h4>
<ul>
<li>SOAP 전송을 위해 사용하는 인코딩이 XML 이기 때문에 바이너리 기반 인코딩 기법에 비해 상대적으로 느림</li>
<li>XML 문서 처리 속도에 대한 비용</li>
<li>REST (Representational State Transfer) 에 비해 상대적으로 복잡함</li>
</ul>
<h3>SOAP 라이브러리 종류</h3>
<p>웹서비스는 개방된 기술을 사용하기 때문에 이기종 간의 통신이 자유로우므로<br />
다양한 프로그래밍 언어를 사용해서 개발할 수 있다는 것 역시 장점입니다.</p>
<p>현존하는 대부분의 언어는 SOAP 을 지원하는 외부 라이브러리를 가지고 있습니다.<br />
Perl 의 경우 <a href="http://search.cpan.org/perldoc?SOAP::Lite">SOAP::Lite</a> 라는 라이브러리가 유명하며<br />
Ruby 의 경우 <a href="http://dev.ctor.org/soap4r">soap4r</a>, Python 의 경우 <a href="http://pywebsvcs.sourceforge.net/">ZSI</a> 등이 널리 쓰입니다.<br />
C 언어 역시 널리 쓰이는 몇 가지 라이브러리가 있는데<br />
문서에서는 다음 세 가지 C 언어 라이브러리에 대해서 살펴봅니다.</p>
<ul>
<li><a href="http://csoap.sourceforge.net/">cSOAP</a></li>
<li><a href="http://live.gnome.org/LibSoup">libsoup</a></li>
<li><a href="http://www.cs.fsu.edu/~engelen/soap.html">gSOAP</a></li>
</ul>
<h4>테스트용 SOAP 서버</h4>
<p>각 라이브러리를 이용한 SOAP 클라이언트를 작성할 때<br />
클라이언트가 제대로 동작하는지 확인을하려면 SOAP 서버가 필요합니다.<br />
SOAP 은 프로그래밍 언어의 제약이 없는 것이 장점이므로<br />
섭씨 및 화씨 온도를 변환하는 간단한 SOAP 서버를<br />
Perl 의 SOAP::Lite 모듈을 이용해서 제작했습니다.</p>
<p>다음은 Perl 로 작성한 SOAP 서버의 예제입니다:</p>
<pre><code>  #!/usr/bin/perl
  #
  # REQUIREMENT:
  #
  #     sudo apt-get install libsoap-lite-perl
  #

  use strict;
  use warnings;

  use SOAP::Transport::HTTP;

  BEGIN {

      package SOAP::Transport::HTTP::Daemon;

      no warnings 'redefine';

      sub handle {
          my $self = shift-&gt;new;
          while (my $c = $self-&gt;accept) {
              while (my $r = $c-&gt;get_request) {

                  print STDERR $r-&gt;content, "\n";

                  $self-&gt;request($r);
                  $self-&gt;SUPER::handle;
                  $c-&gt;send_response($self-&gt;response)
              }
              # replaced -&gt;close, thanks to Sean Meisner &lt;Sean.Meisner@VerizonWireless.com&gt;
              # shutdown() doesn't work on AIX. close() is used in this case. Thanks to Jos Clijmans &lt;jos.clijmans@recyfin.be&gt;
              $c-&gt;can('shutdown')
                  ? $c-&gt;shutdown(2)
                  : $c-&gt;close();
              $c-&gt;close;
          }
      }

      1;
  }

  BEGIN {
      package My::Handler;

      use base qw/SOAP::Transport::HTTP::Daemon/;

      1;
  }

  my $daemon = My::Handler-&gt;new(
      LocalAddr =&gt; 'localhost',
      LocalPort =&gt; 10000,
  );

  $daemon
      -&gt;dispatch_to('Temperatures')
      -&gt;handle;

  BEGIN {
      package Temperatures;

      use base qw/ Exporter SOAP::Server::Parameters /;

      use SOAP::Lite;

      sub c2f {
          my $self = shift;
          my $temp = shift;

          my $f = ((9/5) * $temp) + 32;
          #sleep 3; # check sync or async

          return SOAP::Data-&gt;type('string')-&gt;name(result =&gt; $f),
      }

      sub f2c {
          my $self = shift;
          my $temp = shift;

          my $c = ($temp - 32) * (5/9);
          #sleep 3; # check sync or async

          return SOAP::Data-&gt;type('string')-&gt;name(result =&gt; $c),
      }

      1;
  }
</code></pre>
<p>소스 코드 중 <code>c2f()</code> 함수와 <code>f2c()</code> 함수에 주석 처리한 <code>sleep</code> 구문은<br />
클라이언트에서 사용한 라이브러리가 비동기 방식의 호출을 지원하는지<br />
확인하기 위한 부분입니다.<br />
비동기 방식의 호출을 지원하는 경우 서버에서 요청받은 원격 메소드<br />
호출을 수행할 때 시간 지연이 있을지라도 클라이언트는 요청 즉시<br />
프로그램의 제어권을 가질 수 있습니다.<br />
이론적으로는 어떤 라이브러리를 사용하든 상기 서버와 통신할 수 있어야 합니다.</p>
<p>클라이언트는 <code>http://localhost:10000/Temperatures</code> 주소를 통해<br />
화씨 및 섭씨 온도 변환 웹서비스를 제공받을 수 있습니다.</p>
<h4>cSOAP</h4>
<p>cSOAP 은 순수 C 언어로 구현한 클라이언트/서버 SOAP 라이브러리로<br />
SOAP 1.1 명세를 지원하며 라이센스는 LGPL 입니다.</p>
<p>의존하는 라이브러리 목록은 다음과 같습니다:</p>
<ul>
<li>libxml2 (libdl, libz, libm 에 의존)</li>
<li>libssl (libdl, libcrypto, libz 에 의존): 사용여부 선택 가능</li>
<li>libpthread: nanohttp 서버에서 사용: 윈도우즈 외의 경우 서버에서만 사용</li>
</ul>
<p>UDP 와 HTTP 프로토콜을 이용한 전송을 지원하며 SSL 도 지원합니다.<br />
HTTP 서버 기능 역시 포함하는데 이 부분은 nanoHTTP 모듈에서 구현합니다.<br />
cSOAP 으로 전송되는 XML 구조는 libxml2 라이브러리를 이용해서 처리합니다.<br />
클라이언트 서버간의 UDP 전송시 멀티캐스트 기능과 SOAP-over-UDP 를 지원하며<br />
MIME 첨부 기능, XML 암호화 및 서명을 통한 보안 메시지를 지원합니다.<br />
WS-Inspection 문서 자동 생성 기능도 지원합니다.<br />
그리고 순수 ANSI C 로 구현했기 때문에 윈도우즈, 유닉스, 리눅스 뿐만 아니라<br />
MacOS, OpenVMS, AIX 등의 아키텍처도 지원합니다.</p>
<p>하지만 cSOAP 이 제공하는 문서 자동 생성 기능은 완벽하게 지원하지 않는<br />
것 같으며 특히 WSDL 문서를 이용해서 코드를 자동 생성하는 기능의 경우<br />
비교적 간단한 WSDL 의 경우 문제가 없었으나 ONVIF 공식 홈페이지에서 제공하는<br />
WSDL 문서의 경우 제대로 코드를 생성하지 못하기도 했습니다.<br />
또한 문서의 내용이 릴리스 버전에 비해 갱신이 되지 않아서 간간히 맞지 않는<br />
부분이 있으므로 문서를 참조할 때 유의해야 합니다.</p>
<p>동기 방식의 호출만 지원하며 문서 상에는 비동기 방식의 호출 API 도 나와있으나<br />
실제로 코드를 살펴보면 헤더에만 정의되어 있고 구현이 되어 있지 않아<br />
결과적으로 비동기 방식의 호출은 지원하지 않습니다.</p>
<p>현재 안정 버전은 1.1.0 이며 마지막 릴리스 날짜는 2006년 3월 6일 입니다.<br />
SOAP 명세 자체가 안정화가 되었고 나온지 비교적 시간이 지난 기술이기 때문에<br />
라이브러리 역시 안정화가 되어서 그런지 릴리스 이후 특별한 변화는 없어<br />
메일링 리스트 등의 활동이 저조하므로 사용시 이런 부분을 감안해야 할 것으로 보입니다.</p>
<p>cSOAP 을 사용한 동기 방식의 클라이언트 예제는 다음과 같습니다:</p>
<pre><code>  #include &lt;libcsoap/soap-client.h&gt;
  #include &lt;stdio.h&gt;

  static char *url = "http://localhost:10000";
  static char *urn = "http://localhost:10000/Temperatures";
  static char *method = "c2f";

  int
  main (int argc, char **argv)
  {
    SoapCtx *request;
    SoapCtx *response;
    herror_t err;

    /**
     * Client initialization
     */
    if ((err = soap_client_init_args(argc, argv)) != H_OK)
      {
        printf ("%s():%s [%d]\n", herror_func(err), herror_message(err), herror_code(err));
        herror_release (err);
        exit (1);
      }

    /**
     * Envelope creation
     */
    if ((err = soap_ctx_new_with_method (urn, method, &amp;request)) != H_OK)
      {
        printf ("%s():%s [%d]\n", herror_func(err), herror_message(err), herror_code(err));
        herror_release (err);
        soap_client_destroy ();
        exit (1);
      }

    soap_env_add_item (request-&gt;env, "xsd:int", "temp", "10");

    /**
     * Invocation
     */
    if ((err = soap_client_invoke (request, &amp;response, url, "")) != H_OK)
      {
        printf ("%s():%s [%d]\n", herror_func(err), herror_message(err), herror_code(err));
        herror_release (err);
        soap_ctx_free (request);
        soap_client_destroy ();
        exit (1);
      }

    /**
     * Printout result
     */
    soap_xml_doc_print(response-&gt;env-&gt;root-&gt;doc);
    //xmlDocFormatDump (stdout, response-&gt;env-&gt;root-&gt;doc, 1);

    /**
     * Cleanup
     */
    soap_ctx_free (response);
    soap_ctx_free (request);
    soap_client_destroy ();

    exit (0);
  }
</code></pre>
<p>상기 클라이언트를 빌드하는 방법은 다음과 같습니다:</p>
<pre><code>  gcc csoap-client.c -o csoap-client \
     `pkg-config --cflags libcsoap` \
     `pkg-config --libs libcsoap`
</code></pre>
<h4>libsoup</h4>
<p>libsoup 은 GNOME 환경을 위한 HTTP 클라이언트/서버 라이브러리로 라이센스는 LGPL 입니다.</p>
<p>의존하는 라이브러리 목록은 다음과 같습니다:</p>
<ul>
<li>libglib (libgio, libgobject, libgmodule, libgthread)</li>
<li>libgnutls (libgpg-error, libgcrypt, libz)</li>
<li>libpthread: gnutls 기능에서 사용, 윈도우즈 외의 경우 사용</li>
</ul>
<p>libsoup 의 특징은 다음과 같습니다:</p>
<ul>
<li>GNOME 환경을 위한 HTTP 클라이언트/서버 라이브러리</li>
<li>GObject 와 glib 메인 루프를 사용하고, 콜백을 지원하므로 GNOME 응용과 통합하기 쉬움</li>
<li>비동기 뿐만 아니라 동기 API 도 가지므로 스레드 프로그램에서도 사용 가능</li>
<li>자동 캐시 연결 기능</li>
<li>GnuTLS 를 이용한 SSL 지원</li>
<li>프록시 지원, 인증, SSL 터널링 지원</li>
<li>클라이언트의 Digest, NTLM, 기본 인증 지원</li>
<li>서버의 Digest, 기본 인증 지원</li>
<li>서버 및 클라이언트의 XML-RPC 지원</li>
</ul>
<p>리눅스 및 윈도우와 MacOS 도 지원을하며<br />
glib 기반으로 메인루프와 콜백 API 를 지원합니다.<br />
gnome 프로젝트의 일부로써 gnome 버전과 함께 업데이트 되며<br />
현재 안정 버전은 그놈 버전과 같은 2.27.4 로 2009 년 6월 13일 마지막<br />
git 커밋 로그가 있는 것을 확인했습니다.<br />
최근까지 활발한 활동이 있는 라이브러리인 만큼 메일링 리스트를 통한<br />
지원을 받기 좋을 것으로 보입니다.</p>
<p>특징에서 볼 수 있듯이 사실 libsoup 은 SOAP 과 직접적으로 상관은 없습니다.<br />
여타 SOAP 관련 라이브러리와 비교해 비동기 통신을 지원한다는 점이 특징적인 장점입니다.<br />
하지만 cSOAP 과 마찬가지로 WSDL 관련 코드 생성 등은 지원하지 않으며<br />
SOAP 메시지 전송을 위해 직접 SOAP 헤더 및 본문을 생성해야 하는 것이 단점입니다.</p>
<p>예전 릴리스 버전은 SOAP 전송을 지원했으나 개발팀이 SOAP 관련 기능을<br />
사용하는 개발자가 많지 않다는 판단을 한 후 SOAP 관련 API 및 기능이<br />
라이브러리에서 모두 제거되었습니다.<br />
즉, 현재는 SOAP 에 특화된 어떤 기능도 제공하지 않으며<br />
간단한 XML-RPC 클라이언트/서버 통신만 지원합니다.<br />
다만 SOAP 의 근간이 되는 HTTP 통신을 지원하므로 SOAP 메시지 생성 및 분해 작업을<br />
제외한 SOAP 메시지 통신에만 사용할 수 있습니다.</p>
<p>libsoup 을 사용한 동기 방식의 클라이언트 예제는 다음과 같습니다:</p>
<pre><code>  #include &lt;libsoup/soup.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;string.h&gt;

  static gchar *urn = "http://localhost:10000/Temperatures";

  #define SOAP_BODY "&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;&lt;soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" soap:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"&gt;&lt;soap:Body&gt;&lt;c2f xmlns=\"http://localhost:10000/Temperatures\"&gt;&lt;c-gensym3 xsi:type=\"xsd:int\"&gt;10&lt;/c-gensym3&gt;&lt;/c2f&gt;&lt;/soap:Body&gt;&lt;/soap:Envelope&gt;"

  /**
   * Debug level
   *    - SOUP_LOGGER_LOG_NONE
   *    - SOUP_LOGGER_LOG_MINIMAL
   *    - SOUP_LOGGER_LOG_HEADERS
   *    - SOUP_LOGGER_LOG_BODY
   */
  static SoupLoggerLogLevel debug_level = SOUP_LOGGER_LOG_BODY;

  int
  main (int argc, char **argv)
  {
    SoupSession *session;
    SoupMessage *msg;
    guint        status;

    g_type_init ();
    g_thread_init (NULL);

    /**
     * Create a SoupSession
     *    - soup_session_sync_new
     *    - soup_session_sync_new_with_options
     *    - soup_session_async_new
     *    - soup_session_async_new_with_options
     */
    session = soup_session_sync_new ();

    /**
     * Session features
     *
     *    how to add:
     *      - session-construction time
     *        - SOUP_SESSION_ADD_FEATURE
     *        - SOUP_SESSION_ADD_FEATURE_BY_TYPE
     *      - after session-construction
     *        - soup_session_add_feature()
     *
     *    available features:
     *      - SoupLogger
     *      - SoupCookieJar
     *      - SoupCookieJarText
     */
    if (debug_level)
      {
        SoupLogger *logger;

        logger = soup_logger_new (debug_level, -1);
        soup_session_add_feature (session, SOUP_SESSION_FEATURE (logger));
        g_object_unref (logger);
      }

    /**
     * Creating SoupMessages
     *
     *    SoupMessage: An HTTP request and response
     *
     *    typedef struct {
     *      const char         *method;
     *
     *      guint               status_code;
     *      char               *reason_phrase;
     *
     *      SoupMessageBody    *request_body;
     *      SoupMessageHeaders *request_headers;
     *
     *      SoupMessageBody    *response_body;
     *      SoupMessageHeaders *response_headers;
     *    } SoupMessage;
     *
     *    use soup_message_new()
     *
     *    use SOUP_METHOD_POST for SOAP web-service method request
     *
     *    to modify request or response, use:
     *      - soup_message_set_request()
     *      - soup_message_set_response()
     *
     *    to use more complicated headers and body, use:
     *      - SoupMessage.request_headers with soup_message_headers_append()
     *      - SoupMessage.request_body    with soup_message_body_append()
     *
     */
    msg = soup_message_new (SOUP_METHOD_POST, urn);

    soup_message_headers_append(msg-&gt;request_headers,
                                "Content-Type",
                                "text/xml;charset=UTF-8");

    soup_message_body_append(msg-&gt;request_body, SOUP_MEMORY_COPY, SOAP_BODY, strlen (SOAP_BODY));

    /**
     * Sending a SoupMessage
     *
     *    Synchronously:
     *      - soup_session_send_message()
     *      - unref SoupMessage by hand
     *
     *    Asynchronously:
     *      - soup_session_queue_message() with callback function
     *      - SoupMessage will be unref-ed by automatically
     *
     */
    status = soup_session_send_message (session, msg);

    /**
     * Processing the response
     */
    printf ("response(%d): %s\n", status, msg-&gt;response_body-&gt;data);

    /**
     * Cleanup code
     */
    g_object_unref (G_OBJECT (session));

    return 0;
  }
</code></pre>
<p>상기 클라이언트를 빌드하는 방법은 다음과 같습니다:</p>
<pre><code>  gcc libsoup-client-sync.c -o libsoup-client-sync \
     `pkg-config --cflags libsoup-2.4` \
     `pkg-config --libs libsoup-2.4`
</code></pre>
<p>libsoup 을 사용한 비동기 방식의 클라이언트 예제는 다음과 같습니다:</p>
<pre><code>  /**
   * libsoup-client-async.c:
   *
   * gcc libsoup-client-async.c -o libsoup-client-async \
   *    `pkg-config --cflags libsoup-2.4` \
   *    `pkg-config --libs libsoup-2.4`
   */
  #include &lt;libsoup/soup.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;string.h&gt;

  static GMainLoop *loop;
  static gchar *urn = "http://localhost:10000/Temperatures";

  #define SOAP_BODY "&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;&lt;soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" soap:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"&gt;&lt;soap:Body&gt;&lt;c2f xmlns=\"http://localhost:10000/Temperatures\"&gt;&lt;c-gensym3 xsi:type=\"xsd:int\"&gt;10&lt;/c-gensym3&gt;&lt;/c2f&gt;&lt;/soap:Body&gt;&lt;/soap:Envelope&gt;"

  /**
   * Debug level
   *    - SOUP_LOGGER_LOG_NONE
   *    - SOUP_LOGGER_LOG_MINIMAL
   *    - SOUP_LOGGER_LOG_HEADERS
   *    - SOUP_LOGGER_LOG_BODY
   */
  static SoupLoggerLogLevel debug_level = SOUP_LOGGER_LOG_BODY;

  static void
  got_response (SoupSession *session, SoupMessage *msg, gpointer user_data)
  {
    /**
     * Processing the response
     */
    printf ("response(%u): %s\n", msg-&gt;status_code, msg-&gt;response_body-&gt;data);

    g_main_loop_quit (loop);
  }

  int
  main (int argc, char **argv)
  {
    SoupSession *session;
    SoupMessage *msg;

    g_thread_init (NULL);
    g_type_init ();

    /**
     * Create a SoupSession
     *    - soup_session_sync_new
     *    - soup_session_sync_new_with_options
     *    - soup_session_async_new
     *    - soup_session_async_new_with_options
     */
    session = soup_session_sync_new ();

    /**
     * Session features
     *
     *    how to add:
     *      - session-construction time
     *        - SOUP_SESSION_ADD_FEATURE
     *        - SOUP_SESSION_ADD_FEATURE_BY_TYPE
     *      - after session-construction
     *        - soup_session_add_feature()
     *
     *    available features:
     *      - SoupLogger
     *      - SoupCookieJar
     *      - SoupCookieJarText
     */
    if (debug_level)
      {
        SoupLogger *logger;

        logger = soup_logger_new (debug_level, -1);
        soup_session_add_feature (session, SOUP_SESSION_FEATURE (logger));
        g_object_unref (logger);
      }

    /**
     * Creating SoupMessages
     *
     *    SoupMessage: An HTTP request and response
     *
     *    typedef struct {
     *      const char         *method;
     *
     *      guint               status_code;
     *      char               *reason_phrase;
     *
     *      SoupMessageBody    *request_body;
     *      SoupMessageHeaders *request_headers;
     *
     *      SoupMessageBody    *response_body;
     *      SoupMessageHeaders *response_headers;
     *    } SoupMessage;
     *
     *    use soup_message_new()
     *
     *    use SOUP_METHOD_POST for SOAP web-service method request
     *
     *    to modify request or response, use:
     *      - soup_message_set_request()
     *      - soup_message_set_response()
     *
     *    to use more complicated headers and body, use:
     *      - SoupMessage.request_headers with soup_message_headers_append()
     *      - SoupMessage.request_body    with soup_message_body_append()
     *
     */
    msg = soup_message_new (SOUP_METHOD_POST, urn);

    soup_message_headers_append(msg-&gt;request_headers,
                                "Content-Type",
                                "text/xml;charset=UTF-8");

    soup_message_body_append(msg-&gt;request_body, SOUP_MEMORY_COPY, SOAP_BODY, strlen (SOAP_BODY));

    /**
     * Sending a SoupMessage
     *
     *    Synchronously:
     *      - soup_session_send_message()
     *      - unref SoupMessage by hand
     *
     *    Asynchronously:
     *      - soup_session_queue_message() with callback function
     *      - SoupMessage will be unref-ed by automatically
     *
     */
    soup_session_queue_message (session, SOUP_MESSAGE (msg), got_response, NULL);

    loop = g_main_loop_new (NULL, TRUE);
    g_main_loop_run (loop);
    g_main_loop_unref (loop);

    return 0;
  }
</code></pre>
<p>상기 클라이언트를 빌드하는 방법은 다음과 같습니다:</p>
<pre><code>  gcc libsoup-client-async.c -o libsoup-client-async \
     `pkg-config --cflags libsoup-2.4` \
     `pkg-config --libs libsoup-2.4`
</code></pre>
<h4>gSOAP</h4>
<p>gSOAP 은 Robert A. van Engelen 교수가 C++ 로 제작한 SOAP 라이브러리로<br />
SOAP 1.1 및 SOAP 1.2 명세를 충실히 따르는 안정적인 라이브러리입니다.<br />
gSOAP public 라이센스와 GPL 또는 사이트 라이센스 중 하나를 따를 수 있으며<br />
클라이언트 서버를 모두 지원합니다.<br />
리눅스 및 윈도우, MacOS 등의 플랫폼을 지원하며<br />
의존 라이브러리 없이 자체적으로 필요한 기능을 모두 구현했으며<br />
SOAP 메시지 생성 및 분해도 내부적으로 다 처리해줍니다.<br />
또한 다른 라이브러리와는 달리 wsdl 관련 자동 코드 생성 및<br />
클라이언트 및 서버의 스텁 코드를 자동으로 생성해주는 것은 큰 장점입니다.<br />
현재 안정버전은 2.7.13 으로 2009년 03월 21일 릴리스가 가장 최근 버전입니다.</p>
<p>gSOAP 은 SOAP 관련 클라이언트 및 서버 코드를 자동으로 생성해주므로<br />
프로그래머는 웹서비스에 필요한 메소드를 헤더 파일에 정의만 하면 됩니다.<br />
다음과 같이 섭씨 및 화씨 온도를 변환하는 메소드를 정의한<br />
temperatures.h 파일을 생성합니다:</p>
<pre><code>  int ns__c2f (int temperature, char **result);
  int ns__f2c (int temperature, char **result);
</code></pre>
<p>gSOAP 으로 하여금 자동으로 코드를 생성토록 합니다:</p>
<pre><code>  soapcpp2 -C -c temperatures.h
</code></pre>
<p>-C 옵션은 클라이언트 코드만 생성하도록 하며 -c 옵션은 C++ 가 아니라<br />
C 언어 코드를 생성토록 합니다.</p>
<p>soapcpp2 유틸리티가 자동 생성한 파일 중 ns.nsmap 파일의 내용 중<br />
ns 항목을 접속할 웹서비스에 맞게 수정해합니다:</p>
<pre><code>  #include "soapH.h"
  SOAP_NMAC struct Namespace namespaces[] =
  {
      {"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/*/soap-envelope", NULL},
      {"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/*/soap-encoding", NULL},
      {"xsi", "http://www.w3.org/2001/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance", NULL},
      {"xsd", "http://www.w3.org/2001/XMLSchema", "http://www.w3.org/*/XMLSchema", NULL},
      {"ns", "http://localhost:10000/Temperatures", NULL, NULL},
      {NULL, NULL, NULL, NULL}
  };
</code></pre>
<p>ns 항목을 http://localhost:10000/Temperatures 로 변경하도록 합니다:</p>
<pre><code>      {"ns", "http://localhost:10000/Temperatures", NULL, NULL},
</code></pre>
<p>gSOAP 을 사용한 비동기 방식의 클라이언트 예제는 다음과 같습니다:</p>
<pre><code>  #include "soapH.h"
  #include "ns.nsmap"

  static char *urn = "http://localhost:10000/Temperatures";

  int
  main (int argc, char **argv)
  {
    struct soap soap;
    int input;
    char *c, *f;

    soap_init (&amp;soap);

    input = 10;
    soap_call_ns__c2f (&amp;soap, urn, "", input, &amp;f);

    if (soap.error)
      {
        soap_print_fault (&amp;soap, stderr);
        exit (1);
      }
    else
      printf ("c2f(%d) = %s\n", input, f);

    soap_destroy (&amp;soap);
    soap_end (&amp;soap);

    input = 50;
    soap_call_ns__f2c (&amp;soap, urn, "", input, &amp;c);

    if (soap.error)
      {
        soap_print_fault (&amp;soap, stderr);
        exit (1);
      }
    else
      printf ("f2c(%d) = %s\n", input, c);

    /**
     * Cleanup
     *    - deserialized class instances
     */
    soap_destroy (&amp;soap);

    /**
     * Cleanup
     *    - deserialized data &amp; temporary data
     */
    soap_end (&amp;soap);

    /**
     * Cleanup
     *    - Reset and detach context
     *    - close master/slave sockets and remove callbacks
     */
    soap_done (&amp;soap);

    return 0;
  }
</code></pre>
<p>상기 클라이언트를 빌드하는 방법은 다음과 같습니다:</p>
<pre><code>  gcc -o gsoap-client-async \
     gsoap-client-async.c \
     soapC.c \
     soapClient.c \
     `pkg-config --cflags gsoap` \
     `pkg-config --libs gsoap`
</code></pre>
<p>gSOAP 은 비동기 방식의 원격 메소드 호출을 지원하지 않습니다.<br />
대신 one-way message passing 이라는 방식의 비동기 이벤트 호출<br />
및 응답 처리와 관련한 기능을 클라이언트와 서버에서 지원합니다.<br />
이 기능을 사용하려면 공식 문서 중 다음 항목을 참조합니다:</p>
<ul>
<li><a href="http://www.cs.fsu.edu/~engelen/soapdoc2.html#tth_sEc7.3">7.3  How to Use gSOAP for Asynchronous One-Way Message Passing</a></li>
<li><a href="http://www.cs.fsu.edu/~engelen/soapdoc2.html#tth_sEc7.4">7.4  One-Way Message Passing over HTTP</a></li>
</ul>
<p>하지만 이 방식을 사용하려면 클라이언트 및 서버 양쪽이 모두 지원할<br />
수 있도록 양쪽의 코드를 모두 수정해야 하며 libsoup 에서 볼 수 있는<br />
비동기 방식의 원격 메소드 호출과는 거리가 있습니다.<br />
메일링 리스트에서도 비동기 방식으로 호출하는 방법과 관련한<br />
문의가 많았지만 딱 부러지는 간단한 해결책은 없습니다.</p>
<p>이와 관련해 메일링 리스트에서 Engelen 교수는<br />
<a href="http://markmail.org/message/prgb74c3bbpzqhde">SOAP 이 원래 비동기 방식을 지원하기 설계된 프로토콜이 아니었다</a>는<br />
언급을 하며 비동기 방식을 지원하려면 SOAP 위에 모델을 만들어서<br />
직접 처리해야 한다고 합니다.<br />
gSOAP 의 서버측은 어느정도 비동기 방식의 구조로 작성할 수 있으나<br />
클라이언트 측에서 이를 구현하려면 고민이 필요할 것으로 보입니다.<br />
실제로 클라이언트에서 원격 메소드를 호출하는 부분에 대한<br />
소켓 통신이 이루어지는 부분은 soap.fsend, soap.frecv 등의 부분입니다.<br />
gSOAP 은 내부 메소드를 오버라이딩하는 기능을 제공하는데<br />
이 기능을 이용해서 상기 메소드를 async 하게 처리하는 등의<br />
작업이 필요할 것으로 보입니다.<br />
gSOAP 의 내부 메소드 오버라이딩 기능은 공식 문서 중 다음 항목을 참조합니다:</p>
<ul>
<li><a href="http://www.cs.fsu.edu/~engelen/soapdoc2.html#tth_sEc18.7">18.7 Function Callbacks for Customized I/O and HTTP Handling</a></li>
</ul>
<p>마지막으로 gSOAP 은 스텁 코드를 자동으로 생성하며 바이너리 빌드시<br />
모두 정적 링크를 하기 때문에 상대적으로 바이너리 용량이 커지는 점이 특징입니다.</p>
<h3>정리하며</h3>
<p>SOAP 은 비교적 시간이 지난 기술이며 내부 데이터를 XML 로 처리하기 때문에<br />
속도가 느리다는 단점이 있지만 다양한 이기종 환경을 극복하고 동일한 서비스를<br />
요청 또는 제공할 수 있다는 장점 때문에 호환성이 중요한 비지니스 업무에 적당합니다.<br />
IP 카메라의 ONVIF 명세 채택은 이러한 SOAP 의 장점을 적극 활용한 것이라고<br />
볼 수 있는데 IP 카메라가 ONVIF 를 지원함으로써 HTTP 통신이 가능하고<br />
XML 파싱을 할 수 있는 시스템이라면 어떤 환경에서라도 IP 카메라를 제어할<br />
수 있는 접근성에 대한 우위를 가지게 됩니다.</p>
<p>다양한 SOAP 라이브러리 중 C 언어에서 사용할 수 있는<br />
cSOAP, libsoup, gSOAP 을 살펴보았는데 각 라이브러리의 특징은 다음과 같습니다.<br />
cSOAP 은 용량이 작고 사용하기 간편하지만 릴리스 날짜가 오래된 점이 특징입니다.<br />
libsoup 은 직접적으로 SOAP 을 지원하는 것이 아니라 HTTP 통신을 지원하며<br />
유일하게 동기 및 비동기 통신을 지원합니다.<br />
gnome 프로젝트의 일부로 최근까지 릴리스가  되고 있는 점이 특징입니다.<br />
gSOAP 은 밑바닥부터 거의 직접 구현했기 때문에 의존성이 거의 없으며<br />
SOAP 명세를 제대로 지원하며 최근까지도 릴리스가 되고 있습니다.<br />
또한 SOAP 통신을 위한 스텁 코드 및 WSDL 코드를 자동 생성하는 기능을 제공합니다.<br />
다만 비동기 통신을 지원하지 않으며 의존성이 없는 만큼 라이브러리 용량이 크고<br />
정적으로 바이너리에 링크하는 것이 특징입니다.<br />
라이브러리 마다 고유한 특징을 가지고 있기 때문에 업무에 적용하려면<br />
라이브러리의 기능 및 한계, 그리고 극복 방법에 대한 충분한 숙지가 필요할 것으로 보입니다.</p>
]]></content:encoded>
			<wfw:commentRss>http://bebop.emstone.com/2009/07/28/soap-library-survey/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/2.0/kr/</creativeCommons:license>
	</item>
	</channel>
</rss>

