제4장 UCS 사용 예제

내용 목차

4.1. 프로그램 비정상 종료 관리
4.2. 소켓을 이용한 비동기 통신 프로그램
4.3. RQ를 사용한 프로그램
4.4. 클라이언트 대 서버 프로그램
4.5. 서버 대 서버 프로그램

UCS는 업무 특성에 따라 다양하게 프로그램화하여 사용한다. 본 장에서는 실제 UCS가 사용될 때 다양한 방법으로 프로그램화된 예제를 보여준다.

다음은 비정상 종료 프로그램(core)이 발생했을 때 해당 core 파일을 특정 디렉터리로 이동시키고 연결된 클라이언트에게 비정상 종료 프로그램의 정보를 전달하는 예제이다.

<ucs_svr1.c >

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <dirent.h>
#include <fcntl.h>
#include <usrinc/atmi.h>

char _file_path[100];
int  _cliid[10];

int tpsvrint(int argc, char *argv[])
{
   return 0;
}

int tpsvrdone()
{
   return 0;
}

int usermain(int argc, char *argv[])
{
   int  iRet, i;
   char core_file[50];
   char server_name[50];
   char cur_time[20];
   char *str;
   /* init cliid */
   for (i=0; i<10; i++)
       _cliid[i] = -1;
   strcpy(_file_path, argv[1]);
   sprintf(core_file, "%s/core", _file_path);
   while(1) {
      tpschedule(5);
      iRet = checkCoreFile();
      if (iRet == 1) {
          iRet = getCoreName(core_file, server_name);
          iRet = getCurrentTime(cur_time);
          iRet = moveCoreFile(core_file, server_name, cur_time);
          str = (char *)tpalloc("STRING", NULL, 0);
          sprintf(str, "%s program core !!", server_name);
          for (i=0; i<10; i++) {
              if (_cliid[i] < 0) continue;
              iRet = tpsendtocli(_cliid[i], str, strlen(str), 0);
              if (iRet == -1) {
                  printf("client close connect !!\n");
                  _cliid[i] = -1;
              }
          }
          for (i=0; i<10; i++)
              printf("cliid = %d - %d\n", i, _cliid[i]);
          tpfree(str);
      }
   }
}

int checkCoreFile()
{
   char    server_name[50];
   char    core_file[100];
   struct  dirent *dirent;
   DIR    *dp;
   dp = opendir(_file_path);
   if (dp == NULL) {
       printf("%s directory is not found !\n", _file_path);
       return -1;
   }
   for (dirent = readdir(dp); dirent != NULL; dirent = readdir(dp)) {
       if ( (strlen(dirent->d_name) == 4) &&
            (strncmp(dirent->d_name, "core", 4) == 0)) {
           closedir(dp);
           return 1;
       }
   }
   closedir(dp);
   return -1;
}

int getCoreName(char *filename, char *server)
{
   int fd, cnt, i;
   char buf[6000];
   fd = open(filename, O_RDONLY);
#ifdef _HP
   cnt = read(fd, buf, 144);
#endif
#ifdef _SUN
   cnt = read(fd, buf, 132);
#endif
#ifdef _IBM
   cnt = read(fd, buf, 1759);
#endif
   cnt = read(fd, buf, 1760);
   while(1) {
   cnt = read(fd, buf, 1);
      if (cnt != 1) return -1;
      *server++ = buf[0];
      if (buf[0] == 0) break;
   }
   close(fd);
}

int getCurrentTime(char *cur_time)
{
   struct tm *tm;
   time_t tnow;
   time(&tnow);
   tm = localtime(&tnow);
   sprintf(cur_time, "%04d%02d%02d%02d%02d%02d",
                     tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
                     tm->tm_hour,      tm->tm_min,   tm->tm_sec);
   return 0;
}

int moveCoreFile(char *core, char *server, char *time)
{
   char cmd[100];
   char file_name[50];
   printf("server = [%s]\n", server);
   sprintf(file_name, "core_%s_%s", server, time);
   sprintf(cmd, "mv %s %s/%s", core, _file_path, file_name);
   system(cmd);
   return 0;
}

CONN_TERM(TPSVCINFO *msg)
{
   int   i;
   char *stdata;
   stdata = (char *)msg->data;
   for (i=0; i<10; i++) {
       if (_cliid[i] >= 0) continue;
       _cliid[i] = tpgetclid();
       printf("connect client %d = %d\n", i, _cliid[i]);
       break;
   }
   tpreturn(TPSUCCESS, 0, (char *)stdata, 0, 0);
}

다음은 클라이언트에서 들어오는 소켓을 수락하고, 수락한 소켓에서 들어오는 요청을 tpacall한 후에 그 결과를 다시 클라이언트에 전송하는 예제이다.

<ucs_svr2.c> usermain()

#include <stdio.h>      
#include <stdlib.h>     
#include <string.h>     
#include <unistd.h>     
#include <fcntl.h>      
#include <errno.h>      
#include <signal.h>      
#include <sys/types.h>      
#include <sys/time.h>  
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>    
#include <usrinc/atmi.h>
#include <usrinc/ucs.h>

#ifndef INADDR_NONE
#define INADDR_NONE        0xffffffff
#endif

#define CLIENT_PORT        9345
#define HOST_ADDR          "61.33.32.107"
#define MAX_BUFFER_LEN     4096


/* ----------------------- global variable --------------------------- */
int                client_fd = -1;
char               ip_addr[30];
int                portno;

extern int _cur_clhfd;

/* ----------------------- service initial -------------------------- */
tpsvrinit(int argc, char *argv[])
{
        sleep(5);
        parse_args(argc, argv);

        client_fd = network_connect(ip_addr, portno);        
        if (client_fd > 0)
                 tpsetfd(client_fd);

        printf("ucs_sample:client_fd = %d\n", client_fd);
        printf("ucs_sample: _cur_clhfd(1) = %d\n", _cur_clhfd);
}

tpsvrdone()
{
        if (client_fd > 0) {
                 tpclrfd(client_fd);
                 close(client_fd);
        }                
}

/* ----------------------- main ------------------------------------- */
int usermain(int argc, char *argv[])
{
    int   n;

        /* never return */
        while(1) {
                if (client_fd < 0) {
                        client_fd = network_connect(ip_addr, portno);        
                        if (client_fd > 0)
                                 tpsetfd(client_fd);
                         else {
                                 tpschedule(5);
                                 continue;
                         }
                }
                
        printf("ucs_sample:client_fd = %d\n", client_fd);
        printf("ucs_sample: _cur_clhfd(1) = %d\n", _cur_clhfd);

                if ((n = tpschedule(0)) < 0) {
                        sleep(1);
                        continue;
                }
                                
        printf("ucs_sample: _cur_clhfd(2) = %d\n", _cur_clhfd);
                if (tpissetfd(client_fd)) {
                        if ((n = request_from_client(client_fd)) < 0) {
                                 tpclrfd(client_fd);
                                close(client_fd);
                                client_fd = -1;
                        }
                }
        }
}

/* ----------------------- command argument ------------------------- */
int parse_args(int argc, char *argv[])
{
        int  c;

        portno  = -1;                 
        memset(ip_addr, 0x00, sizeof(ip_addr));
        
        opterr = 0; /* don't want getopt() writing to stderr */
        while ((c = getopt(argc, argv, "i:p:")) != EOF) {
                switch (c) {
                case 'p':       /* port */
                         portno = atoi(optarg);
                           break;                           
                case 'i':       /* ip-addr */
                         strcpy(ip_addr, optarg);
                           break;
                case '?':
                         printf("unrecognized option: -%c", optopt);
                }
        }

        /* default value: portno, shared memory key */
        if (portno <= 0) {
                portno = CLIENT_PORT;                 
                printf("no PORT is set: assumed %d\n", portno);
        }
        if (ip_addr[0] == 0x00) {
                strcpy(ip_addr, HOST_ADDR);
                printf("no IP-ADDR is set: assumed %s\n", ip_addr);
        }
        return 1;
}

/* ----------------------- client request --------------------------- */
int request_from_client(int fd)
{
        int     n, len;
        char    *ptr, buffer[MAX_BUFFER_LEN];

        /* read header */
        memset(buffer, 0x00, sizeof(buffer));
        n = socket_read(fd, buffer, 4);
        if (n <= 0)
                return -1;

        len = atoi(buffer);
        printf("ucs_sample:length : %d\n", len);

        /* read data */
        n = socket_read(fd, &buffer[4], len);
        if (n <= 0) {
                return -1;
        }

        sleep(3);
        len += 4;
        n = socket_write(fd, buffer, len);

        printf("ucs_sample:socket write : n=%d\n", n);
        return n;
}

/* ------------------- client connect for TCP/IP ------------------ */
int network_connect(char *host, int port)
{
        struct sockaddr_in        serv_addr;
        unsigned long        inaddr;
        struct hostent        *hp;
        int    i, fd; 
        
        memset((char *) &serv_addr, 0, sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port   = htons(port);

        /* First try to convert the host name as a dotted-decimal number.
         * Only if that fails do we call gethostbyname(). */
        if ((inaddr = inet_addr(host)) != INADDR_NONE) {
            /* it's dotted-decimal */
            memcpy((char *) &serv_addr.sin_addr, (char *) &inaddr, sizeof(inaddr));
        } else {
            if ((hp = gethostbyname(host)) == NULL) {
                printf("host name error: %s\n", host);
                return(-1);
            }
            memcpy((char *) &serv_addr.sin_addr, hp->h_addr, hp->h_length);
        }

        if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
            printf("can't open stream socket\n");
            return -1;
        }

        if (connect(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) >= 0)
            return fd;

        close(fd);
        return -1;
}

/* ------------------- data read ---------------------------------- */
int socket_read(int fd, char *ptr, int nbytes)
{
    int         nleft, nread;
    char        *ptr2;

    ptr2  = (char *)ptr;
    nleft = nbytes;

    while (nleft > 0) {
        nread = recv(fd, ptr, nleft, 0);
        if (nread < 0) {
           if (errno == EINTR)
              continue;
           else if (errno == EWOULDBLOCK) 
              return (nbytes - nleft);
           return(nread);       /* error, return < 0 */
        } else if (nread == 0)
           break;           /* EOF */
    
       nleft -= nread;
       ptr   += nread;
    }
    return (nbytes - nleft);        /* return >= 0 */
}


/* ------------------- data write --------------------------------- */
int socket_write(int fd, char *ptr, int nbytes)
{
    int nleft, nwritten;

    nleft = nbytes;
    while (nleft > 0) {
        nwritten = send(fd, ptr, nleft, 0);
        if (nwritten <= 0)
           return(nwritten);        /* error */
        
        nleft -= nwritten;
        ptr   += nwritten;
    }    
    return(nbytes - nleft);
}

다음은 fail 큐에 쌓인 데이터를 dequeue하여 다시 호출하는 프로그램 예제이다.

<ucs_svr3.c>

#include    <sys/types.h>   /* required for some of our prototypes */
#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h>
#include    <unistd.h>
#include    <fcntl.h>

#include    <sys/socket.h>
#include    <sys/stat.h>
#include    <sys/un.h>
#include    <netinet/in.h>
#include    <arpa/inet.h>

#include        <usrinc/atmi.h>
#include        <usrinc/tmaxapi.h>

#define         MAX_BUF_SZ      10000
#define         SZ              100
#define         QUEFILE     "rq1"
#define         QUESERVICE  "+fail"

int usermain(int argc, char*argv[])
{
        char svc[XATMI_SERVICE_NAME_LENGTH];
        long   len, n;
        int     try, iFailCnt;
        char *ptr;
        char QueFile[SZ];
        char QueService[SZ];

        strcpy(QueFile, QUEFILE);
        strcpy(QueService, QUESERVICE);

        ptr = (char *)tpalloc("CARRAY", NULL, MAX_BUF_SZ);

        while (1) { /* Endless Loop */
           tpschedule(10); /* Sleep 10 seconds */

           n = 0;
           try = 0;

           iFailCnt = tpqstat(QueFile, TMAX_FAIL_QUEUE); 

           while( (n >= 0) && (try++ < iFailCnt ) ) {
                n = tpdeq(QueFile, QueService, &ptr, &len, TPRQS );

           if (n < 0 ) {
                if (tperrno == TPEMATCH) /* Fail Q empty */
                    ;
                else
                    printf("tpdeq fail[%s]\n", tpstrerror(tperrno));
                continue;
            }
            n = tpextsvcname((char*)ptr, svc);

            if (n < 0) {
                printf("tpextsvcname fail![%s]\n", tpstrerror(tperrno));
                continue;
            }
            n = tpenq(QueFile, svc, (char*)ptr, len, TPRQS);

            if (n < 0) {
                printf("tpenq fail![%s]\n", tpstrerror(tperrno));
                continue;
            }
        }
    }
    return 1;
}

다음은 서버 프로그램에서 루프를 수행하다가 클라이언트에서 LOGIN 서비스를 요청하면 UCS가 응답을 보내주는 예제이다.

설정 파일

*DOMAIN         
tmax1           SHMKEY =79970, MINCLH=1, MAXCLH=3,
                TPORTNO=8844, BLOCKTIME=120
*NODE 
tmaxs2          TMAXDIR = "/user/jaya/tmax3511",
                APPDIR  = "/user/jaya/tmax3511/appbin",
                PATHDIR = "/user/jaya/tmax3511/path",
                TLOGDIR = "/user/jaya/tmax3511/log/tlog",
                ULOGDIR = "/user/jaya/tmax3511/log/ulog",
                SLOGDIR = "/user/jaya/tmax3511/log/slog"
*SVRGROUP 
tmaxs2_nx       NODENAME = "tmaxs2"
*SERVER 
ucs_server      SVGNAME = tmaxs2_nx, SVRTYPE = UCS
*SERVICE 
LOGIN           SVRNAME = ucs_server

클라이언트 프로그램

  1. 클라이언트 프로그램은 실행하면 tpstart()를 하고 LOGIN이라는 서비스를 tpcall()하여, UCS 프로세스에 서비스를 요청한다.

  2. 클라이언트 프로그램에 설정된 tpsetunsol_flag(TPUNSOL_POLL);은 서버 프로세스에서 보내는 메시지를 받겠다는 의미이다.

  3. 클라이언트 프로그램은 서버 프로세스에서 sndbuf에 담아 보낸 "Client Registration Success"라는 메시지를 rcvbuf에서 받아 출력한다.

    printf("After tpcall() received Message from server:%s\n", rcvbuf);
  4. 클라이언트에서 요청이 있으면 서버 프로세스의 loop count가 증가하고, count가 증가하면서 서버 프로세스의 for loop에서 sndbuf에 담아보낸 "Success tpsendtocli [0]" 메시지가 마찬가지로 클라이언트에서도 while loop에서 loop count가 증가하면서 출력된다.

    while(1) {
         tpgetunsol(UNSOL_TPSENDTOCLI, &rcvbuf, &rcvlen, TPBLOCK);
         printf("Loop Count : %d\n", RecvCnt);
         if(rcvlen > 0) {
               printf("Counter : %d #[Received Data from Server : %s]\n", 
                       RecvCnt, rcvbuf);
               RecvCnt ++;
          }
    }

다음은 클라이언트 프로그램의 예제이다.

#include <stdio.h>
#include <usrinc/atmi.h>
#include <usrinc/ucs.h>

main(int argc, char *argv[])
{
        char *sndbuf;
        char *rcvbuf;
        long rcvlen;
        int RecvCnt = 0;

        if(tpstart((TPSTART_T *)NULL) == -1)
        {
                error processing…
        }

        tpsetunsol_flag(TPUNSOL_POLL);

        if((sndbuf = (char *)tpalloc("CARRAY", NULL, 1024)) == NULL)
        {
                error processing…
        }

        if((rcvbuf = (char *)tpalloc("CARRAY", NULL, 1024)) == NULL)
        {
                error processing…
        }

        if(tpcall("LOGIN", sndbuf, 1024, &rcvbuf, &rcvlen, 0) == -1)
        {
                error processing…
        }

        printf("After tpcall() received Message from server:%s\n", rcvbuf);

        while(1)
        {
                tpgetunsol(UNSOL_TPSENDTOCLI, &rcvbuf, &rcvlen, TPBLOCK);
                printf("Loop Count : %d\n", RecvCnt);
                if(rcvlen > 0)
                {
                        printf("Counter : %d #[Received Data from Server : %s]\n", 
                                RecvCnt, rcvbuf);
                        RecvCnt ++;
                }
                if (RecvCnt == 10) break;
        }
        tpfree((char *)sndbuf);
        tpfree((char *)rcvbuf);
        tpend();
}

클라이언트 프로그램 예제의 결과는 다음과 같다.

tmaxs2:/user/jaya/tmax3511/sample/client>ucs_client
After tpcall() received Message from server:Client Registration Success
Loop Count : 0
Counter : 0 #[Received Data from Server : Success tpsendtocli [0]]
Loop Count : 1
Counter : 1 #[Received Data from Server : Success tpsendtocli [1]]
Loop Count : 2
Counter : 2 #[Received Data from Server : Success tpsendtocli [2]]
Loop Count : 3
Counter : 3 #[Received Data from Server : Success tpsendtocli [3]]
Loop Count : 4
Counter : 4 #[Received Data from Server : Success tpsendtocli [4]] 

서버 프로그램

  1. 서버 프로그램은 Tmax가 기동된 후부터 5초를 sleep하고 클라이언트에서 요청이 있을 때까지 "loop execute…0"을 출력하며 계속 무한 루프를 한다.

    sleep(5);
    printf ("loop execute... %d\n", count);

    무한 루프를 하다가 while loop의 마지막 줄에 있는 jobs = tpschedule(-1); 부분에서 클라이언트에서 보낸 요청이 있는지 확인하고, 요청이 없으면 다시 루프하지만 요청이 있을 때에는 그 요청을 받아들이게 된다.

    client_id[num_cli] = tpgetclid();
    printf("client id(clid) = %d\n", client_id[num_cli]);
    num_cli++;
  2. 저장된 클라이언트의 ID 값으로 while loop의 for loop에서는 count 수가 증가하고 그 증가되는 값을 sndbuf에 담아 tpsendtocli() 함수를 사용하여 클라이언트에 서비스를 수행한다.

    for (i = 0; i < num_cli; i++)
    {
         sprintf(sndbuf, "Success tpsendtocli [%d]", count++);
         /* 클라이언트 ID를 참조하여 고객에게 데이터를 보내는 부분 */
         tpsendtocli (client_id[i], sndbuf, 1024, 0);
    }
  3. sndbuf에 클라이언트가 등록되었다는 메시지를 담아 tpreturn() 한다.

    sprintf(sndbuf, "Client Registration Success");
    tpreturn(TPSUCCESS, 0, (char *)sndbuf, 1000, 0);

다음은 서버 프로그램의 예제이다.

#include <stdio.h>
#include <usrinc/atmi.h>
#include <usrinc/ucs.h>

#define MAX_CLI 100

int num_cli;
int client_id[MAX_CLI];
int count;

tpsvrinit(int argc, char *argv[])
{
    num_cli = 0;
    count = 0;
    printf("UCS Type Server tpsvrinit() is call\n");
}

/* Tmax의 UCS 모드에서 main과 같은 부분 */
int usermain(int argc, char *argv[])
{
    int     jobs;
    int     i;
    int     ret;
    char    *sndbuf;
    static int count = 0;

    printf("usermain start\n");

    sndbuf = (char *)tpalloc("CARRAY", NULL, 1024);

    while(1)
    {
          sleep(5);
          printf ("loop execute... %d\n", count);

          for (i = 0; i < num_cli; i++)
          {
                sprintf(sndbuf, "Success tpsendtocli [%d]", count++);

                /* 클라이언트 ID를 참조하여 고객에게 데이터를 보내는 부분 */
                tpsendtocli (client_id[i], sndbuf, 1024, 0);
          }
          jobs = tpschedule(-1); /* while 마지막에 반드시 있어야 함 */
    }
}

LOGIN(TPSVCINFO *msg)
{
     char    *sndbuf;
     int     clid;
     int     ret;
     int     i;

     sndbuf = (char *)tpalloc("CARRAY", NULL, 1024);

     if (num_cli < MAX_CLI)
     {
            /* 클라이언트의 ID 값을 보관하는 부분 */
            client_id[num_cli] = tpgetclid();
            printf("client id(clid) = %d\n", client_id[num_cli]);
            num_cli++;
     }
     sprintf(sndbuf, "Client Registration Success");

     tpreturn(TPSUCCESS, 0, (char *)sndbuf, 1000, 0);
}
tpsvrdone()
{
}

결과

서버 프로그램 예제의 결과는 다음과 같다.

usermain start
UCS Type Server tpsvrinit() is call
usermain start
loop execute... 0
loop execute... 0
loop execute... 0
client id(clid) = 2097152
loop execute... 0
loop execute... 1
loop execute... 2
loop execute... 3
loop execute... 4
loop execute... 5
loop execute... 6
loop execute... 7
loop execute... 8
loop execute... 9
loop execute... 10
loop execute... 11
loop execute... 12
loop execute... 13
loop execute... 14
client id(clid) = 2097153
loop execute... 15
loop execute... 17
loop execute... 19
…..

다음은 3개의 서버 프로세스를 이용하여 하나의 프로세스는 UCS로 계속 루프하고, 다른 하나는 데이터베이스에서 데이터를 선택하여 또 다른 프로세스를 호출하여 다른 테이블에 삽입하는 예제 프로그램이다.

  1. <ucssvr.c>는 UCS 프로세스로, mainsvr.pc에 있는 MAIN이라는 서비스를 계속 tpcall하는 프로그램이다.

  2. UCS 프로세스로부터 tpcall을 받은 <mainsvr.pc>는 데이터베이스에 있는 test_sel이라는 테이블에서 첫 번째 데이터부터 선택하여 <inssvr.pc>에 있는 INS라는 서비스를 tpcall한다.

  3. tpcall을 받은 <inssvr.pc>는 test_ins라는 테이블에 test_sel 테이블에서 선택해온 데이터를 삽입한다. 이 과정이 이루어지면 <mainsvr.pc>는 tx_commit()을 하고 test_sel 테이블에서 inssvr.pc에게 넘겨준 데이터를 삭제한다.

  4. test_sel 테이블에 6개의 데이터가 있기 때문에 동일한 과정을 6번 반복한다.

  5. 삭제할 데이터가 없기 때문에 1403 에러가 발생한다.

설정 파일

*DOMAIN 
tmax1                SHMKEY =79970, MINCLH=1, MAXCLH=3,
TPORTNO=8844, BLOCKTIME=120

*NODE 
tmaxs2               TMAXDIR = "/user/jaya/tmax3511",
                     APPDIR  = "/user/jaya/tmax3511/appbin",
                     PATHDIR = "/user/jaya/tmax3511/path",
                     TLOGDIR = "/user/jaya/tmax3511/log/tlog",
                     ULOGDIR = "/user/jaya/tmax3511/log/ulog",
                     SLOGDIR = "/user/jaya/tmax3511/log/slog"

*SVRGROUP 
tmaxs2_nx            NODENAME = "tmaxs2"
### tms for Oracle ###
tmaxs2_xa            NODENAME = "tmaxs2", DBNAME = ORACLE,
                     OPENINFO = "Oracle_XA+Acc=P/scott/tiger+SesTm=60",
                     TMSNAME  = tms_ora

*SERVER
ucssvr               SVGNAME = tmaxs2_nx, SVRTYPE = UCS, MIN = 1
mainsvr              SVGNAME = tmaxs2_xa, MIN = 1
inssvr               SVGNAME = tmaxs2_xa, MIN = 1

*SERVICE 
MAIN                 SVRNAME = mainsvr
INS                  SVRNAME = ins

test_sel 테이블

SQL> select * from test_sel;
A
--------------------
aaaaa
bbbbb
ccccc
ddddd
eeeee
fffff

6 rows selected.

SQL> select * from test_ins;

no rows selected

서버 프로그램

<ucssvr.c>

#include <stdio.h>
#include <usrinc/atmi.h>
#include <unistd.h>

int usermain(int argc, char *argv[]) /* Tmax의 UCS 모드에서 main과 같은 부분 */
{
        int     ret;
        int     jobs;
        long    len;
        char    *sndbuf, *rcvbuf;

        printf("usermain start\n");
        sndbuf = (char *)tpalloc("STRING", NULL, 0);
        rcvbuf = (char *)tpalloc("STRING", NULL, 0);
        while(1) {
                ret = tpcall("MAIN", sndbuf, 0, &rcvbuf, &len, 0);
                if (ret == -1) {
                    error processing…
                }
                jobs = tpschedule(-1);
                sleep (10);
        }
}

<mainsvr.pc>

#include <stdio.h>
#include <ctype.h>
#include <usrinc/atmi.h>

EXEC SQL include sqlca.h;

#define MAXROW 6
EXEC SQL begin declare section;
        varchar v_a[MAXROW][11];
EXEC SQL end declare section;

MAIN(TPSVCINFO *msg)
{
        char *sndbuf, *rcvbuf;
        int i=0, errno;
        long len, ret;

        printf("[mainsvr] START\n");

        printf("[mainsvr] CURSOR DECLARE\n");
        EXEC SQL DECLARE cur_test_sel CURSOR FOR
        SELECT NVL(a,' ')
        FROM test_sel
        WHERE rownum <= 6;

        printf("[mainsvr] CURSOR OPEN\n");
        EXEC SQL OPEN cur_test_sel;

        printf("[mainsvr] open cursor error : %d\n", sqlca.sqlcode);
        if ( sqlca.sqlcode != 0 ){
                error processing…
        }

        printf("[mainsvr] CURSOR FETCH\n");
        EXEC SQL FETCH cur_test_sel into :v_a;
        if (sqlca.sqlcode < 0) {
                errno = sqlca.sqlcode;
                printf("[mainsvr] Fetch error : %d", errno);
                printf("[mainsvr] CURSOR CLOSE\n");
                EXEC SQL CLOSE cur_test_sel;
                printf("[mainsvr] TPRETURN FAIL\n");
                tpreturn( TPFAIL, errno, (char *)NULL, 0, 0 );
        }
        printf("[mainsvr] CURSOR CLOSE\n");
        EXEC SQL CLOSE cur_test_sel;

        for(i=0; i<MAXROW; i++) {
                sndbuf = (char *)tpalloc("STRING", 0, 0);
                rcvbuf = (char *)tpalloc("STRING", 0, 0);

                v_a[i].arr[v_a[i].len] = 0;
                strcpy(sndbuf, v_a[i].arr);
                printf("[mainsvr] %d : %s / %s\n", i, v_a[i].arr, sndbuf);

                printf("[mainsvr] TX_BEGIN\n");
                ret = tx_begin();
                if (ret < 0) {
                        error processing…
                }
                printf("[mainsvr] INSERT\n");
                if(tpcall("INS", sndbuf, strlen(sndbuf), &rcvbuf, &len, 0)<0) {
                        error processing…
                }
                else { /* Success */
                        printf("[mainsvr] TX_COMMIT\n");
                        EXEC SQL DELETE FROM TEST_SEL
                                WHERE A = :sndbuf;
                        if(sqlca.sqlcode != 0) {
                                printf("[mainsvr] delete error : %d\n",
                                        sqlca.sqlcode);
                                ret = tx_rollback();
                                if (ret < 0) {
                                        error processing…
                                }
                        error processing…
                        }
                        tpfree(sndbuf);
                        tpfree(rcvbuf);
                        ret = tx_commit();
                        if (ret < 0) {
                                error processing…
                        }
                }
        }
        …
        tpreturn( TPSUCCESS, 0, (char *)NULL, 0, 0 );
}

<inssvr.pc>

#include <stdio.h>
#include <ctype.h>
#include <usrinc/atmi.h>

EXEC SQL include sqlca.h;

INS( TPSVCINFO *msg )
{
        char *buf;
        int i=0, errno;
        long len;

        printf("woong : START\n");
        buf = (char *)msg->data;

        printf("%s\n", buf);
        printf("woong : INSERT\n");
        EXEC SQL INSERT INTO TEST_INS VALUES(:buf);
        if (sqlca.sqlcode != 0 ) {
                error processing…
        }
        …
        fflush(stdout);
        tpreturn(TPSUCCESS, 0, (char *)NULL, 0, 0 );
}

결과

서버 프로그램 예제의 결과는 다음과 같다.

[mainsvr] START
[mainsvr] CURSOR DECLARE
[mainsvr] CURSOR OPEN
[mainsvr] open cursor error : 0
[mainsvr] CURSOR FETCH
[mainsvr] CURSOR CLOSE
[mainsvr] 0 : aaaaa / aaaaa
[mainsvr] TX_BEGIN
[mainsvr] INSERT
woong : START
aaaaa
woong : INSERT
woong : TPRETURN SUCCESS
[mainsvr] TX_COMMIT
[mainsvr] 1 : bbbbb / bbbbb
[mainsvr] TX_BEGIN
[mainsvr] INSERT
woong : START
bbbbb
woong : INSERT
woong : TPRETURN SUCCESS
[mainsvr] TX_COMMIT
[mainsvr] 2 : ccccc / ccccc
[mainsvr] TX_BEGIN
[mainsvr] INSERT
woong : START
ccccc
woong : INSERT
woong : TPRETURN SUCCESS
[mainsvr] TX_COMMIT
[mainsvr] 3 : ddddd / ddddd
[mainsvr] TX_BEGIN
[mainsvr] INSERT
woong : START
ddddd
woong : INSERT
woong : TPRETURN SUCCESS
[mainsvr] TX_COMMIT
[mainsvr] 4 : eeeee / eeeee
[mainsvr] TX_BEGIN
[mainsvr] INSERT
woong : START
eeeee
woong : INSERT
woong : TPRETURN SUCCESS
[mainsvr] TX_COMMIT
[mainsvr] 5 : fffff / fffff
[mainsvr] TX_BEGIN
[mainsvr] INSERT
woong : START
fffff
woong : INSERT
woong : TPRETURN SUCCESS
[mainsvr] TX_COMMIT………………………6번째가 끝나고 더 이상 select되는 데이터가 없음.
[mainsvr] TPRETURN SUCCESS
[mainsvr] START
[mainsvr] CURSOR DECLARE
[mainsvr] CURSOR OPEN
[mainsvr] open cursor error : 0
[mainsvr] CURSOR FETCH
[mainsvr] CURSOR CLOSE
[mainsvr] 0 : aaaaa / aaaaa
[mainsvr] TX_BEGIN
[mainsvr] INSERT
woong : START
aaaaa
woong : INSERT
woong : TPRETURN SUCCESS
[mainsvr] TX_COMMIT
[mainsvr] delete error : 1403
[mainsvr] TPRETURN FAIL
[mainsvr] START
[mainsvr] CURSOR DECLARE
[mainsvr] CURSOR OPEN
[mainsvr] open cursor error : 0
[mainsvr] CURSOR FETCH
[mainsvr] CURSOR CLOSE
[mainsvr] 0 : aaaaa / aaaaa
[mainsvr] TX_BEGIN
[mainsvr] INSERT
woong : START
aaaaa
woong : INSERT
woong : TPRETURN SUCCESS
[mainsvr] TX_COMMIT
[mainsvr] delete error : 1403
[mainsvr] TPRETURN FAIL
…………………
…………………
…………………

test_ins 테이블

각 테이블을 선택하면 다음과 같은 결과를 확인할 수 있다.

SQL> select * from test_ins;

NAME
--------------------
bbbbb
ccccc
ddddd
eeeee
fffff
aaaaa

6 rows selected.

SQL> select * from test_sel;

no rows selected