예제
본 장에서는 실제 Tmax SQ 시스템 예제를 통해서 사용법에 대해서 설명한다.
1. 기본 프로그램
RQ 프로그램의 동작은 기본적으로 비동기형 통신과 유사하다. RQ 시스템을 사용하는 가장 기본적인 형태의 프로그램으로 클라이언트는 하나의 RQ를 이용하여 tpenq()로 서비스를 호출하고 tpdeq()로 결과값을 받아온다.
다음은 클라이언트가 tpenq()와 tpdeq()를 이용해서 서비스 결과를 받아오는 RQ 프로그램 프로세스이다.
클라이언트는 tpenq()로 서비스를 호출하며 tpdeq()로 결과값을 받아온다. tpenq()의 플래그를 TPNOFLAGS로 주었을 경우 이 과정은 거의 동일하다. tpenq()의 플래그가 TPNOFLAGS가 아닐 경우 서비스 결과값은 클라이언트가 아닌 서버 측의 RQ 데이터 파일에 저장된다. 즉, 클라이언트는 서비스 수행의 완료를 tpsleep()등을 통해 확인할 수 없다. 개발자가 서비스 완료의 시점을 알아야 할 필요가 있다면 TPNOFLAGS를 설정하여 사용하거나 또는 다른 API들을 이용하여 구현할 수 있다. TPNOFLAGS 외의 플래그를 사용할 경우 서버에서 넘겨주는 urcode값은 무시된다.
서비스명을 명시하고 플래그는 TPRQS를 사용했으며 클라이언트는 tpqstat()을 사용하여 replay 큐에 적재되어 있는 결과 데이터들을 읽어온다. 서비스명을 명시하여 RQ를 사용할 경우 서비스의 스케줄링은 각각의 서비스별로 실행되며 tpenq()로 저장된 순서와는 다를 수 있다.
에러가 발생할 경우의 과정은 tpdeq를 참고한다. 함수에 대한 자세한 설명은 Tmax Reference Guide를 참고한다. |
1.1. 환경설정
다음은 Tmax 환경설정에 대한 예제이다.
*DOMAIN tmax SHMKEY=88000, TPORTNO = 8888 *NODE tmax1 TMAXDIR="/user1/tmax", APPDIR="/user1/tmax/appbin" *SVRGROUP svg1 NODENAME = tmax1, CPC = 4, SVGTYPE=RQMGR *RQ rqtest SVGNAME = svg1 *SERVER svr SVGNAME = svg1 *SERVICE SERVICE SVRNAME = svr
각 절의 설정 항목에 대한 설명은 Tmax Administration Guide의 환경 파일 설정을 참고한다. |
1.2. 클라이언트 프로그램
다음은 클라이언트 프로그램에 대한 예제이다.
#include <stdio.h> #include <usrinc/atmi.h> #include <usrinc/tmaxapi.h> int main(int argc, char *argv[]) { char *buf; long rlen; int rqcount, i; if (argc != 2){ error procesing } if (tpstart((TPSTART_T *)NULL) == -1){ error processing } buf = tpalloc("CARRAY", NULL, 0); if (buf == NULL){ error processing } strcpy(buf, argv[1]); if (tpenq("rqtest", "SERVICE", buf, strlen(buf), TPRQS) == -1){ error processing } ... rqcount = tpqstat("rqtest", TMAX_RPLY_QUEUE); for(i = 0;i < rqcount;i++){ ... if(tpdeq("rqtest", "SERVICE", &buf, &rlen, TPRQS) == -1){ error processing } ... } tpfree((char *)buf); tpend(); }
2. UCS 사용 프로그램
tpenq() – tpdeq()라는 간단한 구조의 RQ 프로그램도 Tmax의 다양한 프로세스 관리 유형을 이용하여 개발한다면 그 사용 범위가 매우 다양해진다. 본 절에서는 Tmax의 독자적인 방식인 UCS 방식을 이용한 다양한 프로그래밍 기법을 설명한다.
클라이언트가 요청하는 일련의 작업들이 순서대로 수행되어야 할 필요가 있고 각 서버 프로그램의 수행시간이 길 경우 클라이언트는 전체 서비스 기간 동안 블록 상태로 기다려야 한다. 하지만 RQ를 이용한다면 클라이언트는 원하는 서비스 내용을 RQ에 저장하고 바로 다음 작업을 수행할 수 있으며 서버에서는 서비스 요청 내용을 RQ로부터 순서대로 읽어서 수행할 수 있다.
다음은 UCS 사용를 사용하는 프로그램의 프로세스이다.
클라이언트에서 원하는 서비스명과 데이터를 구조체에 저장하여 여러 번 tpenq()를 하며 이때 서비스명은 NULL을 준다. 이 데이터들은 Reply 큐에 쌓이게 되며 UCS 서버에서는 큐에서 데이터를 읽어 해당 서비스로 데이터를 보내 서비스를 호출한다.
2.1. 환경설정
다음은 Tmax 환경설정에 대한 예제이다.
*DOMAIN tmax SHMKEY=88000, TPORTNO = 8888 *NODE tmax1 TMAXDIR="/user1/tmax", APPDIR="/user1/tmax/appbin" *SVRGROUP svg1 NODENAME = tmax1, CPC = 4, SVGTYPE=RQMGR *RQ rqenq SVGNAME = svg1 rqdeq SVGNAME = svg1 *SERVER svr1 SVGNAME = svg1 svr2 SVGNAME = svg1, SVRTYPE = UCS *SERVICE SERVICE1 SVRNAME = svr1 SERVICE2 SVRNAME = svr1 SERVICE3 SVRNAME = svr1
각 절의 설정 항목에 대한 설명은 Tmax Administration Guide의 환경 파일 설정을 참고한다. |
2.2. 클라이언트 프로그램
다음은 클라이언트 프로그램에 대한 예제이다.
#include <stdio.h> #include <sys/time.h> #include <usrinc/atmi.h> #include <usrinc/tmaxapi.h> #include “../sdl/demo.s” int main(int argc, char *argv[]) { struct *buf1, *buf2, *buf3 long rlen; int rqcount, i; struct timeval tval; if (argc != 4){ error processing } if (tpstart((TPSTART_T *)NULL) == -1){ error processing } buf1 = (struct rqsvc *)tpalloc("STRUCT", “rqsvc”, 0); buf2 = (struct rqsvc *)tpalloc("STRUCT", “rqsvc”, 0); buf3 = (struct rqsvc *)tpalloc("STRUCT", “rqsvc”, 0); if (buf1 == NULL || buf2=NULL || buf3==NULL){ error processing } strcpy(buf1->svc, “SERVICE1”); strcpy(buf1->data, argv[1]); strcpy(buf2->svc, “SERVICE2”); strcpy(buf2->data, argv[2]); strcpy(buf3->svc, “SERVICE3”); strcpy(buf3->data, argv[3]); /*서비스명을 NULL로 주어 Reply 큐에 데이터를 송신한다.*/ if (tpenq("rqenq", NULL, buf1, 0, TPRQS) == -1){ error processing } if (tpenq("rqenq", NULL, buf2, 0, TPRQS) == -1){ error processing } if (tpenq("rqenq", NULL, buf3, 0, TPRQS) == -1){ error processing } tpfree((char *)buf1); tpfree((char *)buf2); tpfree((char *)buf3); tpend(); }
2.3. 서버 프로그램
다음은 서버 프로그램에 대한 예제이다.
#include <stdio.h> #include <usrinc/atmi.h> #include <usrinc/ucs.h> #include <usrinc/tmaxapi.h> #include “../sdl/demo_sdl.h” int usermain(int argc, char *argv[]) { struct rqsvc *buf; char *sndbuf; long rlen; int count, i, ret; buf = (struct rqsvc *)tpalloc("STRUCT", “rqsvc”, 0); if (buf == NULL){ error processing } sndbuf = tpalloc("STRING", NULL, 0); if (sndbuf == NULL){ error processing } while(1){ tpschedule(10); /*Reply 큐의 데이터 갯수를 알아낸다.*/ count = tpqstat("rqenq", TMAX_RPLY_QUEUE); printf("count = %d\n", count); for (i = 0; i < count ; i++){ /*Reply 큐에 있는 데이터를 중 서비스 명이 NULL인 데이터를 송신한다.*/ if (tpdeq("rqenq", NULL, (char **)&buf, &rlen, TPRQS) == -1){ error processing } buf=(struct rqsvc *)buf; strcpy(sndbuf, buf->data); /*순차적으로 서비스를 수행한다.*/ if (tpcall(buf->svc, sndbuf, 0, (char **)&buf, (long *)&rlen, TPNOFLAGS) == -1){ error processing } ... } } return 1; }
3. Fail 큐 복구 프로그램
여러 가지 원인으로 발생한 Fail 큐의 데이터는 상황에 따라 적절한 방식으로 처리해야 한다. 가장 간단하게는 관리 툴을 사용하여 큐의 내용을 삭제하는 방법도 있지만 사용자가 원하는 방식으로 처리하고 싶다면 이를 대행하는 프로그램을 만들어야 한다.
다음은 UCS 방식의 프로그램으로 Fail 큐를 복구하는 프로그램의 프로세스이다.
10초 간격으로 Fail 큐의 데이터를 읽어 들이며 tpextsvcname()으로 해당하는 서비스를 찾은 후 특정 서비스의 데이터는 파기하고 나머지는 다시 해당 서비스의 Request 큐로 넣어준다. tpreissue()는 데이터를 읽어서 해당 서비스로 보내는 과정을 한 번에 수행하지만 위와 같이 상황에 따라 다른 행동을 하는 경우에는 사용할 수 없다.
3.1. 환경설정
다음은 Tmax 환경설정에 대한 예제이다.
*DOMAIN tmax SHMKEY=88000, TPORTNO = 8888 *NODE tmax1 TMAXDIR="/user1/tmax", APPDIR="/user1/tmax/appbin" *SVRGROUP svg1 NODENAME = tmax1, CPC = 4, SVGTYPE=RQMGR *RQ rqtest SVGNAME = svg1, BOOT = WARM *SERVER svr1 SVGNAME = svg1 svr2 SVGNAME = svg1 svr3 SVGNAME = svg1, SVRTYPE = UCS *SERVICE SERVICE1 SVRNAME = svr1 SERVICE2 SVRNAME = svr2 STOP SVRNAME = svr2
각 절의 설정 항목에 대한 설명은Tmax Administration Guide의 환경 파일 설정을 참고한다. |
3.2. 서버 프로그램
다음은 서버 프로그램에 대한 예제이다.
#include <stdio.h> #include <usrinc/atmi.h> #include <usrinc/tmaxapi.h> int usermain(int argc, char *argv[]) { char *buf, svcname[16]; long rlen; int failcount, i, ret; buf = tpalloc("STRING", NULL, 0); if (buf == NULL){ error processing } while(1){ tpschedule(10); /*Fail 큐의 개수를 알아낸다.*/ failcount = tpqstat("rqtest", TMAX_FAIL_QUEUE); for (i = 0; i < failcount ; i++){ /*Fail 큐의 데이터를 수신한다.*/ if (tpdeq("rqtest", _rq_sub_queue_name[TMAX_FAIL_QUEUE], &buf, &rlen, TPRQS) == -1){ error processing } /*서비스명을 알아온다.*/ if (tpextsvcname(buf, svcname) == -1){ error processing } /* 읽어온 데이터가 “STOP” 서비스이면 skip한다. */ if (strcomp(svcname, “STOP”)) { /*해당 서비스명으로 tpenq 한다.*/ ret=tpenq("rqtest", svcname, buf, rlen, TPRQS); if (ret<0) { error processing } } } } return 1; }