본 장에서는 UCS 프로그램 구성 및 환경설정 및 컴파일 방법에 대해 기술한다.
UCS(User Control Server)란, 프로그램의 처리 흐름을 미들웨어에서 제어하지 않고, 사용자가 직접 제어할 수 있는 Tmax 고유의 프로그램 형태이다. 이를 이용한 프로그램과 프로세스를 각각 UCS 프로그램 및 UCS 프로세스라고 한다.
클라이언트의 요청이 없어도 정보 전달이 필요한 업무(증권 시세 정보, notify 등), 작업 스케줄링 업무 및 대외기관과의 연동 업무 등에 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 }
다음은 예제 프로그램에 대한 간략한 설명이다.
최초로 기동할 때 tpsvrinit()을 수행하고 usermain()으로 들어온다.
라인 30, num_cli값이 0이므로, for 문을 빠져나온다.
라인 36, tpschedule()을 통해 클라이언트로부터 서비스 요청이 있는지 또는 tmdown 명령을 받았는지 확인한다.
라인 40, 클라이언트로부터 LOGIN SERVICE 요청이 온 경우 수행한다. 요청이 없는 경우 tpschedule()을 빠져나온다.
라인 56, tpgetclid()를 통해 접속된 클라이언트 정보를 global(이하 전역) 변수인 client_id에 저장한 후 num_cli값을 증가시킨다.
라인 61, LOGIN SERVICE를 요청한 클라이언트에 응답 데이터를 전송한다.
라인 36, tpschedule()을 빠져나온다.
라인 30, num_cli값이 양수값이므로 for 문을 수행한다.
라인 32, tpsendtocli()를 통해 client_id에 저장된 클라이언트에 해당 정보를 전송한다(이 부분이 비요청 메시지를 전달하는 부분이다).
3 ~ 9 단계를 반복하여 수행한다.
tpschedule()에서 tmdown 명령을 받았다면 tpsvrdone()을 수행한 후 프로세스가 종료된다.
UCS 서버 프로그램은 다음과 같은 모듈과 라이브러리로 구성된다.
위와 같이 UCS 프로그램은 1개의 모듈과 1개의 라이브러리로 구성되며, usermain()의 모듈 내에는 반드시 tpschedule()을 호출해야 한다.
UCS 프로그램은 위와 같은 프로그램 구성을 통해 사용자가 능동적으로 제어할 수 있고, 이를 이용해 다양한 업무를 수행할 수 있는 여러 가지 API를 제공한다. API의 프로토타입은 다음 경로에 정의되어 있다.
$(TMAXDIR)/usrinc/ucs.h
주요 API의 프로토타입은 다음과 같다. 각 함수에 대한 자세한 내용은 “제3장 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)
UCS 프로그램으로부터 서비스를 제공받는 클라이언트 프로그램의 경우 일반적인 프로그램과 거의 유사한 형식이며, 다음의 2가지 설정을 반드시 포함해야 한다.
UCS 프로그램으로부터 전송되는 데이터를 수신하는 설정
UCS 프로그램으로부터 전송되는 데이터를 처리하는 설정
클라이언트 프로그램에서 사용하는 함수 중 UCS 프로그램으로부터 전송되는 데이터를 수신할 수 있도록 설정하는 함수는 다음과 같다.
각 함수에 대한 자세한 내용은 “제3장 UCS 함수”를 참고한다.
환경설정 파일의 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
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 내용은 다를 수 있다.