예제

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

1. 메시지 전송 프로그램

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

figure basic1
메시지 전송 프로그램 흐름
  1. 클라이언트(Client1)는 string 타입의 버퍼에 입력된 문자열을 복사해서 서비스를 호출한다.

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

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

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

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;
}

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);
}

1.4. 프로그램 컴파일

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

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

2. 메시지 저장 프로그램

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

figure basic2
메시지 저장 프로그램 흐름
  1. 클라이언트는 사용자의 입력을 받아서 HMS로 Queue 타입의 메시지를 전송한다.

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

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

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

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;
}

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);
}

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

2.5. 프로그램 컴파일

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

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