gSOAP 사용하기

SOAP 라이브러리 기술조사에 이어 gSOAP 라이브러리를 사용하는데 필요한 내용을 정리해 보았습니다.

사용자는 gSOAP 라이브러리에서 제공하는 다음 두가지 명령을 사용하여 클라이언트/서버 코드를 생성합니다.

wsdl2h

  • C와 C++을 위한 WSDL 파서 입니다. 이 명령을 통해 gSOAP이 스텁(stub) 코드와 스켈레톤(skeleton) 코드를 생성하는데 바탕이 되는 헤더 파일을 생성합니다.

soapcpp2

  • wsdl2h로 만든 헤더 파일을 기반으로 C와 C++을 위한 스텁 코드와 스켈레톤 코드를 생성합니다.
  • soapH.h soapC.c : 데이터 자료형을 위한 XML 시리얼라이저 (serializer) 입니다. 즉, XML 스키마 상의 anyURI, token 과 같은 자료형을 그와 매칭되는 C/C++ 자료형으로 변환하고, 처리합니다.
  • soapClient.c : 클라이언트 측 스텁 코드 입니다. 클라이언트 서비스 함수를 호출하기만 하면 됩니다.
  • soapServer.c : 서버 측 스켈레톤 코드 입니다. 서버는 서비스 함수를 구현해야 합니다.
  • typemap.dat : 사용자가 네임스페이스의 어미(prefix)를 지정하거나 자료형 맵핑을 변경할 수 있습니다.
  • [service_name].nsmap : 해당 서비스에서 사용하는 실제적인 네임스페이스 정의(코드) 입니다.

메모리 관리

gSOAP을 이용하여 서버/클라이언트를 작성할 때, 사용자는 클라이언트 요청, 서버 응답에 해당하는 파라미터에 값을 넣어주게 됩니다. 이 때, 메모리 할당이 필요할 경우 gSOAP에서 제공하는 메모리 할당 API를 사용하면, soap 서비스를 종료할 때, 정확히는 soap_end()를 호출 할 때, 자동으로 할당한 메모리를 해제해 줍니다.

  • soap_malloc () : malloc()에 대한 gSOAP 렙퍼 함수
  • soap_strdup () : strdup()에 대한 gSOAP렙퍼 함수
  • soap_dealloc () : 동적으로 할당한 메모리 해제

서버 동작

기본적으로 gSOAP은 비동기 방식을 지원하지 않는다고 합니다. 따라서 서비스를 제공하기 위해서 주로 쓰레드를 사용하는 것 같습니다.

서버의 기본 동작은 다음과 같을 것입니다.

서버 (기본 프로세스/쓰레드)

  1. soap_new () : soap 객체 생성
  2. soap_bind () : bind 랩퍼 함수
  3. soap_accept() : accept 랩퍼 함수
  4. soap_copy () : soap 문맥 복사

서버 (실제 서비스를 제공하는 쓰레드)

  1. soap_serve() : 최종적으로 사용자가 작성한 서비스를 호출합니다.
  2. soap_destroy () : C++ 객체와 관련된 동적 메모리 해제
  3. soap_end () :  임시 데이터 등 메모리 해제
  4. soap_free() : soap 객체 해제

서버는 soapStub.h 파일에서 Service Operation 에 해당하는 함수(서비스)를 구현하면 되고, 클라이언트는 soapStub.h 파일에서 주석으로 Stubs 라고 명시된 부분의 함수를 이용하여 서비스를 이용하면 됩니다. 다음은 간단한 서버 예제입니다.

int
main(int argc, char **argv)
{
   struct soap soap, *tsoap;
   pthread_t tid;
   int m, s;
   soap_init2 (&soap, SOAP_IO_KEEPALIVE, SOAP_IO_KEEPALIVE);
   soap.max_keep_alive = 100;
   soap.accept_timeout = 600;
   m = soap_bind (&soap, NULL, 18000, BACKLOG);
   if (m < 0)
     {
       soap_print_fault (&soap, stderr);
       exit (1);
     }
  fprintf(stderr, "Socket connection successful %d\n", m);
  for (count = 0; count & gt; = 0; count++)
   {
     soap.socket_flags = MSG_NOSIGNAL;
     soap.accept_flags = SO_NOSIGPIPE;
     s = soap_accept (&soap);
     if (s < 0)
       {
         if (soap.errnum)
           soap_print_fault (&soap, stderr);
         else
           fprintf (stderr, "Server timed out\n");
           break;
       }
     fprintf (stderr, "Accepts socket %d connection from IP %d.%d.%d.%d\n",
              s,
              (int)(soap.ip >> 24)&0xFF,
              (int)(soap.ip >> 16)&0xFF,
              (int)(soap.ip >> 8)&0xFF,
              (int)soap.ip&0xFF);
     tsoap = soap_copy (&soap);
     pthread_create (&tid,
                            NULL,
                            (void *(*)(void *)) process_request,
                            (void *) tsoap);
   }
  return 0;
}

void *
process_request(void *soap)
{
   pthread_detach (pthread_self ());
   ((struct soap*) soap)->recv_timeout = 300;
   ((struct soap*) soap)->send_timeout = 60;
   soap_serve ((struct soap*) soap);
   soap_destroy ((struct soap*) soap);
   soap_end ((struct soap*) soap);
   soap_free ((struct soap*) soap);
   return NULL;
}
Creative Commons License
This work, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 2.0 Korea License.
This entry was posted in Development and tagged . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">