UCS 프로그램

본 장에서는 UCS 프로그램 구성 및 환경설정 및 컴파일 방법에 대해 기술한다.

1. 개요

UCS(User Control Server)란, 프로그램의 처리 흐름을 미들웨어에서 제어하지 않고, 사용자가 직접 제어할 수 있는 Tmax 고유의 프로그램 형태이다. 이를 이용한 프로그램과 프로세스를 각각 UCS 프로그램 및 UCS 프로세스라고 한다.

클라이언트의 요청이 없어도 정보 전달이 필요한 업무(증권 시세 정보, notify 등), 작업 스케줄링 업무 및 대외기관과의 연동 업무 등에 UCS가 사용된다.

2. UCS 프로그램 구성

UCS 프로그램은 usermain()에 대한 구현부가 있어야 하고, 컴파일할 때 UCS 라이브러리(libsvrucs.a / libsvrucs.so)와 링크되어야 한다. 기본적으로 usermain()은 무한루프 형태로 구현된다. 즉, usermain()이 종료(함수 반환)되면, 해당 프로세스는 tpsvrdone()을 수행하고 종료하기 때문이다. usermain()은 main()이 종료되면 해당 프로세스가 종료되는 것과 같다.

UCS 프로그램을 작성할 때는 tpschedule()을 통해 위 클라이언트로부터 전송된 데이터나 Tmax 커널로부터 전송된 종료 명령을 받기 때문에, usermain()의 무한루프 내에 tpschedule()가 항상 존재해야 한다는 것을 주의해야 한다.

다음은 특정 정보를 접속된 클라이언트에게 비요청 메시지 형태로 전송하는 usermain()의 간단한 예제이다.

+1   #include <stdio.h>
+2   #include <usrinc/atmi.h>
+3   #include <usrinc/ucs.h>
+4
+5   #define MAX_CLI 10
+6   int num_cli;
+7   int client_id[MAX_CLI];
+8   int count;
+9
+10  int
+11  tpsvrinit(int argc, char *argv[])
+12  {
+13    num_cli = 0;
+14    count = 0;
+15  }
+16
+16  int
+17  usermain(int argc, char *argv[])  /* Tmax의 ucs 모드에서 main과 같은 부분 */
+18  {
+19     int         jobs;
+20     int         i;
+21     int         ret;
+22     char        *sndbuf;
+23     static int count = 0;
+24
+25     printf("usermain start\n");
+26
+27     sndbuf = (char *)tpalloc("CARRAY", NULL, 1024);
+28
+29     while(1) {
+30        for  (i = 0; i < num_cli; i++) {
+31              sprintf(sndbuf, "Success tpsendtocli [%d] 012345678901234\n", count);
+32              tpsendtocli (client_id[i], sndbuf, 1024, 0);
+33         }
+34         count++;
+35         sleep(1);
+36         jobs = tpschedule(-1);
+37     }
+38  }
+39
+40  LOGIN(TPSVCINFO *msg) /* Tmax의 SERVICE 부분 */
+41  {
+42        char        *sndbuf;
+43        int         clid;
+44        int         ret;
+45        int         i;
+46
+47        printf("msg->data = [%.*s]\n", msg->len, msg->data);
+48        fflush(stdout);
+49
+50        sndbuf = (char *)tpalloc("CARRAY", NULL, 1024);
+51
+52        printf("Success transaction");
+53        sprintf(sndbuf, "Success transaction");
+54
+55        if (num_cli < MAX_CLI) {
+56            client_id[num_cli] = tpgetclid();
+57            printf("client id(clid) = %d\n", client_id[num_cli]);
+58            num_cli++;
+59        }
+60
+61        tpreturn(TPSUCCESS, 0, (char *)sndbuf, 1024, 0);
+62  }

다음은 예제 프로그램에 대한 간략한 설명이다.

  1. 최초로 기동할 때 tpsvrinit()을 수행하고 usermain()으로 들어온다.

  2. 라인 30, num_cli 값이 0이므로, for 문을 빠져나온다.

  3. 라인 36, tpschedule()을 통해 클라이언트로부터 서비스 요청이 있는지 또는 tmdown 명령을 받았는지 확인한다.

  4. 라인 40, 클라이언트로부터 LOGIN SERVICE 요청이 온 경우 수행한다. 요청이 없는 경우 tpschedule()을 빠져나온다.

  5. 라인 56, tpgetclid()를 통해 접속된 클라이언트 정보를 global(이하 전역) 변수인 client_id에 저장한 후 num_cli 값을 증가시킨다.

  6. 라인 61, LOGIN SERVICE를 요청한 클라이언트에 응답 데이터를 전송한다.

  7. 라인 36, tpschedule()을 빠져나온다.

  8. 라인 30, num_cli값이 양수값이므로 for 문을 수행한다.

  9. 라인 32, tpsendtocli()를 통해 client_id에 저장된 클라이언트에 해당 정보를 전송한다(이 부분이 비요청 메시지를 전달하는 부분이다).

  10. 3 ~ 9 단계를 반복하여 수행한다.

  11. tpschedule()에서 tmdown 명령을 받았다면 tpsvrdone()을 수행한 후 프로세스가 종료된다.

2.1. 서버 프로그램

UCS 서버 프로그램은 다음과 같은 모듈과 라이브러리로 구성된다.

  • $(TMAXDIR)/lib/libsvrucs.a 또는 $(TMAXDIR)/lib/shared/libsvrucs.so

    프로그램의 main()과 각종 UCS 관련 API 등을 포함하는 라이브러리이다. UCS 프로그램을 생성할 때 항상 링크해야 한다.

  • int tpsvrinit(int argc, char *argv[])

    프로그램이 기동할 때 한 번 수행된다. 대부분 전역 변수 초기화나 Non-XA의 경우 데이터베이스 연결 등을 구현한다.

  • int tpsvrdone()

    프로그램이 종료할 때 한 번 수행된다. 대부분 사용한 리소스의 반환이나 Non-XA의 경우 데이터베이스 연결 해제 등을 구현한다.

  • int usermain(int argc, char *argv[])

    실제 애플리케이션의 로직이 구현되는 부분이다. usermain()의 모듈에서 반환되면, tpsvrdone()을 수행하고 프로세스가 종료되는 형태이기 때문에, 대부분 무한루프 형태로 구현된다.

    클라이언트의 요청 데이터나 tmdown 명령을 받기 위해 tpschedule()이 항상 필요하다. tpschedule()이 호출되지 않으면 Tmax 서버가 종료되지 않으며, 종료하려면 tmdown –i 형태로 종료한다.

figure 1 3
Figure 1. UCS 서버 프로그램의 구성

위와 같이 UCS 프로그램은 1개의 모듈과 1개의 라이브러리로 구성되며, usermain()의 모듈 내에는 반드시 tpschedule()을 호출해야 한다.

UCS 프로그램은 위와 같은 프로그램 구성을 통해 사용자가 능동적으로 제어할 수 있고, 이를 이용해 다양한 업무를 수행할 수 있는 여러 가지 API를 제공한다. API의 프로토타입은 다음 경로에 정의되어 있다.

$(TMAXDIR)/usrinc/ucs.h

주요 API의 프로토타입은 다음과 같다. 각 함수에 대한 자세한 내용은 UCS 함수를 참고한다.

  • 모든 UCS 프로그램에서 사용되는 API

    • int tpschedule(int sec)

    • int tpuschedule(int usec)

  • 비요청 메시지 전송에 이용되는 API

    • int tpsendtocli(int clid, char *data, long len, long flags)

    • int tpgetclid(void)

  • Non-Tmax와의 비동기 통신을 위한 API

    • int tpsetfd(void)

    • int tpissetfd(void)

    • int tpclrfd(void)

    • int tpgetctx(CTX_T *ctxp)

    • int tpcancelctx(CTX_T *ctxp)

    • CTX_T *tpsavectx()

    • int tprelay(char *svc, char *data, long len, long flags, CTX_T *ctxp)

  • UCS 내에서 tpacall(비동기 통신) 함수를 사용할 때 이용되는 callback API

    • int tpregcb(void)

    • int tpunregcb(void)

2.2. 클라이언트 프로그램

UCS 프로그램으로부터 서비스를 제공받는 클라이언트 프로그램의 경우 일반적인 프로그램과 거의 유사한 형식이며, 다음의 2가지 설정을 반드시 포함해야 한다.

  • UCS 프로그램으로부터 전송되는 데이터를 수신하는 설정

  • UCS 프로그램으로부터 전송되는 데이터를 처리하는 설정

클라이언트 프로그램에서 사용하는 함수 중 UCS 프로그램으로부터 전송되는 데이터를 수신할 수 있도록 설정하는 함수는 다음과 같다.

함수 설명

tpsetunsol_flag

tpstart()를 이용하여 Tmax와 연결할 때 사용한 flag 값을 재설정하는 함수이다. 보통 비요청 메시지를 받을 것인지 받지 않을 것인지의 flag를 설정한다.

tpsetunsol

클라이언트에서 사용하는 함수로, 수신한 비요청 메시지를 처리하는 루틴을 설정하는 함수이다.

tpgetunsol

클라이언트에서 사용하는 함수로, 비요청 메시지 수신 함수이다.

각 함수에 대한 자세한 내용은 UCS 함수를 참고한다.

3. UCS 환경설정 및 컴파일

3.1. 환경설정

환경설정 파일의 SERVER 절에 SVGNAME 항목을 설정한 후 SVRTYPE 항목은 UCS를 지정한다.

다음은 UCS 환경 파일의 예이다.

*DOMAIN
tmax1         SHMKEY =79970, MINCLH=1, MAXCLH=3,
TPORTNO=8844, BLOCKTIME=120, RACPORT=3443
*NODE
tmaxs1  MAXDIR = "/user1/jaya/tmax3511",
        APDIR  = "/user1/jaya/tmax3511/appbin",
        PATHDIR = "/user1/jaya/tmax3511/path",
        TLOGDIR = "/user1/jaya/tmax3511/log/tlog",
        ULOGDIR = "/user1/jaya/tmax3511/log/ulog",
        SLOGDIR = "/user1/jaya/tmax3511/log/slog"
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
svg1                NODENAME = "tmaxs1"
svg2                NODENAME = "tmaxs2"

*SERVER
ucssvr1             SVGNAME = svg1,
                    SVRTYPE = UCS, 
                    CPC = 5          # UCS와 CLH 간의 채널수
ucssvr2             SVGNAME = svg2,
                    SVRTYPE = UCS

*SERVICE
SVC1                SVRNAME = ucssvr1

3.2. 컴파일

UCS 서버 프로그램은 컴파일할 경우 UCS 라이브러리(libsvrucs.a 혹은 libsvrucs.so)와 링크되어야 한다.

프로그램 안에서도 $TMAXDIR/usrinc/ucs.h가 include되어야 하고, Makefile 내의 TMAXLIBS에 반드시 -lsvrucs를 포함해야 한다.

다음은 32bit Solaris에서 UCS 서버 프로그램을 컴파일하기 위한 Makefile의 예이다.

# Server makefile
TARGET  = $(COMP_TARGET)
APOBJS  = $(TARGET).o
SDLFILE  = demo.s

# Solaris의 경우
LIBS      = -lsvrucs -lsocket –lnsl -nodb

# 다른 OS일 경우
LIBS    = -lsvrucs -nodb
OBJS    = $(APOBJS) $(SDLOBJ) $(SVCTOBJ)
SDLOBJ  = ${SDLFILE:.s=_sdl.o}
SDLC    = ${SDLFILE:.s=_sdl.c}
SVCTOBJ = $(TARGET)_svctab.o
CFLAGS  = -O -I$(TMAXDIR)
APPDIR  = $(TMAXDIR)/appbin
SVCTDIR = $(TMAXDIR)/svct
LIBDIR  = $(TMAXDIR)/lib

#
.SUFFIXES : .c
.c.o:
$(CC) $(CFLAGS) -c $<
#
# server compile
#
$(TARGET): $(OBJS)
        $(CC) $(CFLAGS) -L$(LIBDIR) -o $(TARGET) $(OBJS) $(LIBS)
        mv $(TARGET) $(APPDIR)/.
        rm -f $(OBJS)
$(APOBJS): $(TARGET).c
        $(CC) $(CFLAGS) -c $(TARGET).c
$(SVCTOBJ):
        touch $(SVCTDIR)/$(TARGET)_svctab.c
        $(CC) $(CFLAGS) -c $(SVCTDIR)/$(TARGET)_svctab.c
$(SDLOBJ):
        $(TMAXDIR)/bin/sdlc -i ../sdl/$(SDLFILE)
        $(CC) $(CFLAGS) -c ../sdl/$(SDLC)
#
clean:
        -rm -f *.o core $(TARGET)

운영체제에 따라 Makefile 내용은 다를 수 있다.