제5장 예제

본 장에서는 간단한 애플리케이션 예제를 통해서 API의 기본적인 사용법과 전체적인 흐름을 설명한다.

5.1. 메시지 전송 프로그램

다음은 클라이언트와 서버에서 HMS API를 사용하여 메시지를 주고받는 간단한 프로그램 흐름이다.

[그림 5.1] 메시지 전송 프로그램 흐름

메시지 전송 프로그램 흐름


  1. 클라이언트(Client1)는 string 타입의 버퍼에 입력된 문자열을 복사해서 서비스를 호출한다.

  2. 서버의 서비스 루틴에서는 이 문자열을 받아서 소문자를 대문자로 변경한 뒤 HMS로 메시지를 전송한다.

  3. 클라이언트(Client2)는 일정 시간이 지난 뒤 HMS로부터 메시지를 수신받는다.

5.1.1. HMS 환경설정

다음은 HMS 환경설정 파일 예제이다.

*DOMAIN
hms     SHMKEY = 74347,          
        TPORTNO = 8808
 
*NODE
Locke2  TMAXDIR ="/home/tmax5/tmax",
        APPDIR ="/home/tmax5/tmax/appbin/",
        MAXSESSION = 100
 
*SVRGROUP
hms01   NODENAME = "Locke2",  CPC = 1, SVGTYPE = "HMS", RESTART = Y, 
        OPENINFO = "ORACLE_XA+Acc=P/scott/tiger+SesTm=60",
        HMSINDEX = 2, HMSMSGLIVE = 1, HMSMAXTHR = 2, HMSMAXDBTHR = 5,
        HMSNAME = hms_ora
svg1    NODENAME = "Locke2"


*HMS
queue01 SVGNAME = hms01, BOOT = "WARM", TYPE = "QUEUE"
topic01 SVGNAME = hms01, BOOT = "WARM", TYPE = "TOPIC"

*SERVER
svr     SVGNAME = svg1

*SERVICE
SVC     SVRNAME = svr

5.1.2. 클라이언트 프로그램

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

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <usrinc/atmi.h>
#include <usrinc/hmsapi.h>

int main(int argc, char **argv)
{
    char *sndbuf, *rcvbuf;
    long rcvlen, sndlen;
    HMS_SHND *sess;
    HMS_CHND *cons;
    hms_msg_t *msg;

    if (argc != 2) {
        printf("Usage : %s <message>\n\n", argv[0]);
        exit(1);
    }

    if (tmaxreadenv("tmax.env", "TMAX") == -1) {
        printf("error: tmaxreadenv() failed - %d\n", tperrno);
        exit(1);
    }

    if (tpstart((TPSTART_T *) NULL) == -1) {
        printf("error: tpstart() fail - %d\n", tperrno);
        exit(1);
    }

    if ((sndbuf = (char *)tpalloc("STRING", NULL, 0)) == NULL) {
        printf("error: sendbuf alloc failed !\n");
        tpend();
        exit(1);
    }   
 
    if ((rcvbuf = (char *)tpalloc("STRING", NULL, 0)) == NULL) {
        printf("error: recvbuf alloc failed !\n");
        tpfree((char *)sndbuf);
        tpend();
        exit(1);
    }   
 
    strcpy(sndbuf, argv[1]);

    if(tpcall("SVC", sndbuf, 0, &rcvbuf, &rcvlen, 0)==-1){
        printf("error: Can't send request to service SVC\n");
        tpfree((char *)sndbuf);
        tpfree((char *)rcvbuf);
        tpend();
        exit(1);
    }

    sleep(5);

    /* RECV MESSAGE FROM HMS */
    if ((sess = hms_create_session("hms01", 0, HMS_AUTO_ACK, 0)) == NULL) {
        printf("error: hms_create_session() failed tperrno = %d\n", tperrno);
        tpend();
        exit(1);
    }

    if ((cons = hms_create_receiver(sess, "queue01", "cons01", NULL, NULL, 0))
              == NULL) {
        printf("error: hms_create_receiver() failed tperrno = %d\n", tperrno);
        tpend();
        exit(1);
    }

    /* ALLOCATION */
    if ((msg = hms_alloc(sess, 1024)) == NULL) {
        printf("error: hms_alloc() failed tperrno = %d\n", tperrno);
        tpend();
        exit(1);
    }

    /* RECV MESSAGE */
    if (hms_recvex(cons, &msg, 5, 0) == -1) {
        printf("error: hms_recvex() failed tperrno = %d\n", tperrno);
        hms_free(msg);
        tpend();
        exit(1);
    }

    /* GET BODY */
    rcvlen = 1024;
    if (hms_get_body(msg, rcvbuf, &rcvlen) == -1) {
        printf("error: hms_get_body() failed tperrno = %d\n", tperrno);
        hms_free(msg);
        tpend();
        exit(1);
    }

    printf("HMS MESSAGE : %s\n", rcvbuf);

    /* CLOSE RECEIVER */
    if (hms_close_receiver(cons, 0) == -1) {
        printf("error: hms_close_receiver() failed tperrno = %d\n", tperrno);
        hms_free(msg);
        tpend();
        exit(1);
    }
    
    /* CLOSE SESSION */
    if (hms_close_session(sess, 0) == -1) {
        printf("error: hms_close_session() failed tperrno = %d\n", tperrno);
        hms_free(msg);
        tpend();
        exit(1);
    }

    hms_free(msg);
    tpend();

    return 0;
}

5.1.3. 서버 프로그램

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

<svr.c>

#include <stdio.h>
#include <stdlib.h>
#include <usrinc/atmi.h>
#include <usrinc/hmsapi.h>

HMS_SHND *sess = NULL;
HMS_CHND *prod = NULL;

int tpsvrinit(int argc, char **argv)
{
    while(1) {
        sess = hms_create_session("hms01", 0, HMS_AUTO_ACK, 0);
        if (sess != NULL) {
            break;
        }
        if (tperrno != TPENOREADY) {
            printf("hms_create_session(hms01) : FAIL tperrno = %d\n", tperrno);
            return -1;
        }
    }
    prod = hms_create_sender(sess, "queue01", "prod_svc", 0);
    if (prod == NULL) {
        printf("hms_create_sender() : FAIL tperrno = %d\n", tperrno);
        return -1;
    }
    return 1;
}

int tpsvrdone()
{
    hms_close_sender(prod, 0);
    hms_close_session(sess, 0);
    return 1;
}

SVC(TPSVCINFO *msg)
{
    int n, i;
    hms_msg_t *hmsmsg = NULL;
    char *data = msg->data;
    int  len = msg->len, asize;
    printf("SVC STARTED!\n");

    /* TOUPPER */
    for (i = 0; i < len; i++)
        data[i] = toupper(data[i]);

    /* ALLOCATION */
    asize = len +1024;
    hmsmsg = hms_alloc(sess, asize);
    if (hmsmsg == NULL) {
        printf("hms_alloc : fail tperrno = %d\n", tperrno);
        tpreturn(TPFAIL, 0, NULL, 0, 0);
    }
    
    /* SET BODY */
    n = hms_set_body(hmsmsg, data, len);
    if (n < 0) {
        hms_free(hmsmsg);
        printf("hms_set_body : fail tperrno = %d\n", tperrno);
        tpreturn(TPFAIL, 0, NULL, 0, 0);
    }
    
    /* SEND : hms01, persistent */
    n = hms_sendex(prod, hmsmsg, HMS_DLV_PERSISTENT, 0, 0, 0);
    if (n < 0) {
        hms_free(hmsmsg);
        printf("hms_sendex(prod) : fail tperrno = %d\n", tperrno);
        tpreturn(TPFAIL, 0, NULL, 0, 0);
    }

    /* FREE */
    hms_free(hmsmsg);
    
    printf("SVC SUCCESS!\n");
    tpreturn(TPSUCCESS, 0, NULL, 0, 0);
}

5.1.4. 프로그램 컴파일

클라이언트/서버 프로그램은 Tmax 애플리케이션을 컴파일하는 과정과 동일하게 컴파일한다.

참고

프로그램 컴파일에 대한 자세한 내용은 "Tmax Application Development Guide"를 참고한다.

5.2. 메시지 저장 프로그램

다음은 서버/클라이언트 프로그램에서 HMS 전달받은 메시지를 데이터베이스에 저장하는 프로그램의 흐름이다.

[그림 5.2] 메시지 저장 프로그램 흐름

메시지 저장 프로그램 흐름

  1. 클라이언트는 사용자의 입력을 받아서 HMS로 Queue 타입의 메시지를 전송한다.

  2. 서버측에서는 비동기 세션을 통해 소비자(Consumer)를 생성하고 메시지가 전송될 경우 ASYNC 서비스가 이 메시지를 수신한다.

  3. ASYNC 서비스는 수신받은 메시지를 데이터베이스에 Insert한다.

5.2.1. HMS 환경설정

다음은 HMS 환경설정에 대한 예제이다.

*DOMAIN
hms     SHMKEY = 74347,          
        TPORTNO = 8808

*NODE
Locke2  TMAXDIR ="/home/tmax5/tmax",
        APPDIR  ="/home/tmax5/tmax/appbin/",
        MAXSESSION = 100
 
*SVRGROUP
hms01   NODENAME = "Locke2",  CPC = 1, SVGTYPE = "HMS", RESTART = Y, 
        OPENINFO = "ORACLE_XA+Acc=P/scott/tiger+SesTm=60",
        HMSINDEX = 2, HMSMSGLIVE = 1, HMSMAXTHR = 2, HMSMAXDBTHR = 5,
        HMSNAME = hms_ora
svg1    NODENAME = "Locke2", RESTART = N, 
        OPENINFO = "ORACLE_XA+Acc=P/scott/tiger+SesTm=60",
        DBNAME = "ORACLE", TMSNAME = tms_ora, MINTMS = 1

*HMS
queue01 SVGNAME = hms01, BOOT = "WARM", TYPE = "QUEUE"
topic01 SVGNAME = hms01, BOOT = "WARM", TYPE = "TOPIC"

*SERVER
async   SVGNAME = svg1, CLOPT = "-- -i"

*SERVICE
ASYNCSVC   SVRNAME = async

5.2.2. 클라이언트 프로그램

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

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <usrinc/atmi.h>
#include <usrinc/hmsapi.h>


int main(int argc, char **argv)
{
    long len;
    HMS_SHND *sess;
    HMS_PHND *prod;
    hms_msg_t *msg;
    char *data;
    int no;

    if (argc != 3) {
        printf("Usage : %s <no> <message>\n\n", argv[0]);
        exit(1);
    }

    if (tmaxreadenv("tmax.env", "TMAX") == -1) {
        printf("error: tmaxreadenv() failed - %d\n", tperrno);
        exit(1);
    }

    if (tpstart((TPSTART_T *) NULL) == -1) {
        printf("error: tpstart() fail - %d\n", tperrno);
        exit(1);
    }

    len = strlen(argv[2]);
    data = argv[2];
    no = atoi(argv[1]);

    /* SEND MESSAGE TO HMS */
    if ((sess = hms_create_session("hms01", 0, HMS_AUTO_ACK, 0)) == NULL) {
        printf("error: hms_create_session() failed tperrno = %d\n", tperrno);
        tpend();
        exit(1);
    }

    if ((prod = hms_create_sender(sess, "queue01", "prod01", 0)) == NULL) {
        printf("error: hms_create_sender() failed tperrno = %d\n", tperrno);
        tpend();
        exit(1);
    }

    /* ALLOCATION */
    if ((msg = hms_alloc(sess, len + 1024)) == NULL) {
        printf("error: hms_alloc() failed tperrno = %d\n", tperrno);
        tpend();
        exit(1);
    }

    /* SET BODY */
    if (hms_set_body(msg, data, len) == -1) {
        printf("error: hms_set_body() failed tperrno = %d\n", tperrno);
        hms_free(msg);
        tpend();
        exit(1);
    }

    /* SET PROPERTY */
    if (hms_set_property(msg, "NO", HMS_INT, (char *)&no, sizeof(int)) == -1) {
        printf("error: hms_set_property() failed tperrno = %d\n", tperrno);
        hms_free(msg);
        tpend();
        exit(1);
    }

    /* SEND MESSAGE */
    if (hms_sendex(prod, msg, HMS_DLV_PERSISTENT, 0, 0, 0) == -1) {
        printf("error: hms_sendex() failed tperrno = %d\n", tperrno);
        hms_free(msg);
        tpend();
        exit(1);
    }

    if (hms_close_sender(prod, 0) == -1) {
        printf("error: hms_close_sender() failed tperrno = %d\n", tperrno);
        hms_free(msg);
        tpend();
        exit(1);
    }
    
    if (hms_close_session(sess, 0) == -1) {
        printf("error: hms_close_session() failed tperrno = %d\n", tperrno);
        hms_free(msg);
        tpend();
        exit(1);
    }

    hms_free(msg);
    tpend();

    return 0;
}

5.2.3. 서버 프로그램

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

<async.pc>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <usrinc/atmi.h>
#include <usrinc/hmsapi.h>

HMS_SHND *sess;
HMS_CHND *cons;
int svrinit_start = 0;

void abend_callback(HMS_SHND *session)
{
    printf("START ABEND_CALLBACK FUNCTION\n");
    hms_close_session(session, 0); 
    printf("hms_close_session success\n");
    while (1) {
        sess = (HMS_SHND *) hms_create_async_session("hms01", abend_callback, 0);
        if (sess == NULL) {
            if (tperrno == TPENOREADY) {
                usleep(500000);
                continue;
            }
            printf("hms_create_session() : FAIL [%d]\n\n", tperrno);
            return;
        }
        break;
    }
    cons = (HMS_CHND *) hms_create_receiver(sess, "queue01", "consasync", NULL, 
           "ASYNCSVC", 0);
    if (cons == NULL) {
        printf("hms_create_receiver() : FAIL tperrno = %d\n\n", tperrno);
        return;
    }
    printf("END ABEND_CALLBACK FUNCTION\n");
}

int tpsvrinit(int argc, char **argv)
{
    int c;
    while ((c = getopt(argc, argv, "i")) != EOF) {
        switch (c) {
            case 'i':
                svrinit_start = 1;
                break;
        }
    }
    if (svrinit_start == 1) {
        printf("ASYNC SERVICE svrinit()\n");
        while(1) {
            sess = (HMS_SHND *) hms_create_async_session("hms01", abend_callback, 
            0);
            if (sess == NULL) {
                if (tperrno == TPENOREADY) {
                    usleep(500000);
                    continue;
                }
                printf("ASYNC SERVICE hms_create_async_session() failed, 
                        tperrno[%d]\n", tperrno);
                return;
            }
            break;
        }
        cons = (HMS_CHND *) hms_create_consumer(sess, "queue01", HMS_QUEUE, 
                "consasync", "", "ASYNCSVC", 0);
        if (cons == NULL)
            printf("ASYNC SERVICE hms_create_consumer() failed, tperrno[%d]\n", 
                    tperrno);
            return -1;
        }
        printf("ASYNC SERVICE svrinit() success\n");
    }
    return 1;
}

int tpsvrdone()
{
    if (svrinit_start == 1) {
        printf("ASYNC SERVICE svrdone()\n");
        hms_close_consumer(cons, 0);
        hms_close_session(sess, 0);
    }
    return 1;
}

/* DB INSERT */
EXEC SQL include sqlca.h;

EXEC SQL begin declare section;
int no;
char message[128];
EXEC SQL end declare section;

int DBInsert( int n, char *data )
{
    printf("UPDATE START!!!\n");
    memset( message, 0x00, sizeof(message) );
    no = n;
    strcpy(message, data);

    EXEC SQL insert into hmstest(no, message) values(:no, :message);

    if ( sqlca.sqlcode != 0 ){
        printf( "insert failed sqlcode = %d\n",sqlca.sqlcode );
        return -1;
    }

    return 1;
}

ASYNCSVC(TPSVCINFO *svc)
{
    hms_msg_t *msg;
    char *data;
    long llen = 4096;
    int prop = 0;
    int type;

    printf("ASYNC SERVICE CALLED\n");
    msg = (hms_msg_t *)svc->data;

    if ((data = (char *)tpalloc("CARRAY", NULL, 4096)) == NULL) {
        printf("ASYNC SERVICE tpalloc return failed. tperrno[%d]\n", 
                tperrno);
        tpreturn(TPFAIL, TPFAIL_ACK, svc->data, svc->len, 0);
    }

    if (hms_get_body(msg, data, &llen) < 0) {
        printf("ASYNC SERVICE hms_get_body() return failed. tperrno[%d]\n", 
                tperrno);
        tpreturn(TPFAIL, TPFAIL_ACK, svc->data, svc->len, 0);
    }
    data[llen] = '\0';

    llen = sizeof(int);
    if (hms_get_property(msg, "NO", &type, (char *)&prop, &llen) < 0) {
        printf("ASYNC SERVICE hms_get_property() return failed. tperrno[%d]\n", 
                tperrno);
    }
    printf("ASYNC SERVICE RECV MESSAGE, BODY[%s], PROPERTY[NO:%d]\n", data, prop);

    if (DBInsert(prop, data) == -1)
        tpreturn(TPFAIL, TPFAIL_ACK, svc->data, svc->len, 0);
    tpreturn(TPSUCCESS, 0, svc->data, svc->len, 0);
}

5.2.4. 데이터베이스 스크립트

테이블 작성 스크립트

다음은 Oracle 테이블 작성 스크립트이다.

sqlplus scott/tiger << EOF
    create table hmstest (
      no number(7),
      message char(128)
    );
EOF

테이블 및 데이터 출력 스크립트

다음은 Oracle 테이블 및 데이터 출력 스크립트이다.

sqlplus scott/tiger << EOF
desc hmstest;
select * from hmstest;
select count(*) from hmstest;
EOF

5.2.5. 프로그램 컴파일

서버/클라이언트 프로그램은 Tmax 애플리케이션을 컴파일하는 과정과 동일하게 컴파일한다.

참고

프로그램 컴파일에 대한 자세한 내용은 "Tmax Application Development Guide"를 참고한다.