내용 목차
본 장에서는 Tmax 시스템에서 제공하는 고유의 기능을 사용하기 위한 예제를 설명한다.
본 절에서는 Tmax에서 사용하는 3가지 통신형인 동기형, 비동기형, 대화형 애플리케이션의 간단한 예제를 통해 전체적인 흐름에 대해 설명한다.
클라이언트는 STRING 버퍼에 문자열을 복사해서 서비스를 호출하고, 서버의 서비스 루틴은 이 문자열을 받아서 대문자열로 바꾸어 반환하는 프로그램이다.
공통 프로그램
프로그램 파일 | 설명 |
---|---|
sample.m | Tmax 환경설정 파일이다. |
클라이언트 프로그램
프로그램 파일 | 설명 |
---|---|
sync_cli.c | 클라이언트 프로그램이다. |
서버 프로그램
프로그램 파일 | 설명 |
---|---|
syncsvc.c | 대문자로 바꾸는 서비스 프로그램이다. |
Makefile | Tmax에서 제공되는 Makefile로 수정해야 한다. |
클라이언트 프로그램
기능 | 설명 |
---|---|
Tmax 연결 | 기본 연결(클라이언트 정보 없음) |
버퍼 유형 | STRING |
통신 유형 | tpcall()을 이용한 동기형 통신 |
서버 프로그램
기능 | 설명 |
---|---|
서비스 | TOUPPERSTR |
데이터베이스 연결 | 없음 |
다음은 Tmax 환경 파일의 예제이다.
<sample.m>
*DOMAIN resrc SHMKEY = 77990, MAXUSER = 256 *NODE tmax TMAXDIR = "/home/tmax", APPDIR = "/home/tmax/appbin", PATHDIR = "/home/tmax/path", TLOGDIR = "/home/tmax/log/tlog", ULOGDIR = "/home/tmax/log/slog", SLOGDIR = "/home/tmax/log/ulog" *SVRGROUP svg1 NODENAME = tmax *SERVER syncsvc SVGNAME = svg1, MIN = 1, MAX = 5, CLOPT = " –e $(SVR).err –o $(SVR).out " *SERVICE TOUPPERSTR SVRNAME = syncsvc
다음은 클라이언트 프로그램의 예제이다.
<sync_cli.c>
#include <stdio.h> #include <string.h> #include <usrinc/atmi.h> main(int argc,char *argv[]) { char *sendbuf, *recvbuf; long rlen; if (argc != 2) { fprintf(stderr,“Usage: $ %s string \n”,argv[0]); exit(1); } if (tpstart((TPSTART_T*)NULL) == -1) { fprintf(stderr,“Tpstart failed\n”); exit(1); } if ((sendbuf = tpalloc(“STRING”,NULL,0)) == NULL) { fprintf(stderr,“Error allocation send buffer\n”); tpend(); exit(1); } if ((recvbuf = tpalloc(“STRING”,NULL,0)) == NULL) { fprintf(stderr,“Error allocation recv buffer\n”); tpend(); exit(1); } strcpy(sendbuf ,argv[ 1 ] ) ; if ( tpcall(“TOUPPERSTR”,sendbuf,0,&sendbuf,&rlen, TPNOFLAGS) == -1) { fprintf(stderr,“Can’t send request to service TOUPPER->%s!\n”, tpstrerror(tperrno)) ; tpfree(sendbuf) ; tpfree(recvbuf) ; tpend(); exit(1); } printf(“Sent value:%s\n ”,sendbuf ); printf(“Returned value:%s\n ”,recvbuf ); tpfree(sendbuf); tpfree(recvbuf); tpend( );
다음은 서버 프로그램의 예제이다.
<syncsvc.c>
#include <stdio.h> #include <usrinc/atmi.h> TOUPPERSTR(TPSVCINFO *msg) { int i; for (i = 0; i < msg->len ; i++) msg->data[i] = toupper(msg->data[i]); msg->data[i] = ‘\0’; tpreturn(TPSUCCESS, 0, msg->data, 0, TPNOFLAGS); }
클라이언트는 STRUCT 버퍼의 멤버에 문자열을 복사해서 서비스를 호출하고, 서버의 서비스 루틴은 이 문자열을 받아서 소문자열 혹은 대문자열로 바꾸어 반환하는 프로그램이다. 클라이언트는 비동기형 통신으로 TOUPPER 서비스를 요청하고 다시 동기형으로 TOLOWER 서비스를 호출하여 결과를 받은 후 앞서 요청한 TOUPPER 서비스의 수행 결과를 받는다.
공통 프로그램
프로그램 파일 | 설명 |
---|---|
demo.s | 구조체 버퍼를 정의한다. |
sample.m | Tmax 환경설정 파일이다. |
클라이언트 프로그램
프로그램 파일 | 설명 |
---|---|
async_cli.c | 클라이언트 프로그램이다. |
서버 프로그램
프로그램 파일 | 설명 |
---|---|
asyncsvc.c | 대문자/소문자로 바꾸는 서비스 프로그램이다. |
Makefile | Tmax에서 제공되는 Makefile로 수정해야 한다. |
클라이언트 프로그램
기능 | 설명 |
---|---|
Tmax 연결 | 기본 연결 |
버퍼 유형 | STRUCT |
통신 유형 | 동기형 및 비동기형 |
서버 프로그램
기능 | 설명 |
---|---|
서비스 | TOUPPER, TOLOWER |
데이터베이스 연결 | 없음 |
통신 유형 | 동기형 및 비동기형 |
다음은 비동기형 통신에서 사용하는 구조체 버퍼이다.
<demo.s>
struct strdata { int flag; char sdata[20]; };
다음은 Tmax 환경 파일 예제이다.
<sample.m>
*DOMAIN resrc SHMKEY = 77990, MAXUSER = 256 *NODE tmax TMAXDIR = "/home/tmax", APPDIR = "/home/tmax/appbin", PATHDIR = "/home/tmax/path" *SVRGROUP svg1 NODENAME = tmax *SERVER asyncsvc SVGNAME = svg1, MIN = 1, MAX = 5 *SERVICE TOUPPER SVRNAME = asyncsvc TOLOWER SVRNAME = asyncsvc
다음은 클라이언트 프로그램의 예제이다.
<async_cli.c>
#include <stdio.h> #include <string.h> #include <usrinc/atmi.h> #include “../sdl/demo.s” main(int argc,char *argv[ ]) { struct strdata *sendbuf, *sendbuf1; long dlen,clen; int cd; if (argc != 3) { fprintf(stderr, “Usage: $ %s string STRING\n”, argv[0], argv[1]); exit(1) ; } if (tpstart((TPSTART_T *)NULL) == -1) { fprintf(stderr, “TPSTART_T failed\n”); exit(1) ; } sendbuf = (struct strdata *)tpalloc(“STRUCT”, “strdata”, 0); if ( sendbuf == NULL) { fprintf(stderr, “Error allocation send buffer\n”); tpend () ; exit(1) ; } sendbuf1 = (struct strdata *)tpalloc(“STRUCT”, “strdata”, 0); if (sendbuf1 == NULL) { fprintf(stderr, “Error allocation send1 buffer\n”); tpend(); exit(1) ; } strcpy(sendbuf->sdata, argv[1]); strcpy(sendbuf1->sdata, argv[2]); if ((cd = tpacall(“TOUPPER”, (char *)sendbuf, 0, TPNOFLAGS)) == -1) { fprintf(stderr, “Toupper error -> %s”, tpstrerror(tperrno)); tpfree((char *)sendbuf); tpend(); exit(1) ; } if (tpcall(“TOLOWER”,(char *)sendbuf1,0,(char **)&sendbuf1, &dlen, TPSIGRSTRT) == -1) { fprintf(stderr, “Tolower error -> %s”, tpstrerror(tperrno)); tpfree((char *)sendbuf); tpend(); exit(1) ; } if (tpgetrply(&cd, (char **)&sendbuf, &clen, TPSIGRSTRT) == -1) { fprintf(stderr, “Toupper getrply error -> %s”, tpstrerror(tperrno)); tpfree((char *)sendbuf); tpend(); exit(1) ; } printf(“Return value %s\n %s\n”, sendbuf -> sdata, sendbuf1 -> sdata); tpfree((char *)sendbuf); tpfree((char *)sendbuf1); tpend() ; }
다음은 서버 프로그램의 예제이다.
<asyncsvc.c>
#include <stdio.h> #include <usrinc/atmi.h> #include “../sdl/demo.s” TOUPPER(TPSVCINFO *msg) { int i = 0; struct strdata *stdata; stdata = (struct strdata *)msg -> data; while (stdata->sdata[ i ] != ‘\0’) { stdata->sdata[ i ] = toupper(stdata->sdata[ i ]); i++ ; } tpreturn(TPSUCCESS, 0, (char *)stdata, 0, TPNOFLAGS); } TOLOWER(TPSVCINFO *msg) { int i = 0; struct strdata *stdata; stdata = (struct strdata *)msg -> data; while ( stdata->sdata[ i ] != ‘\0’) { stdata->sdata[ i ] = tolower(stdata->sdata[ i ]); i++; } tpreturn(TPSUCCESS, 0, (char *)stdata, 0, TPNOFLAGS); }
클라이언트는 사용자의 입력을 받아 STRING 버퍼를 통해 고유번호를 보내며, 서버의 서비스 루틴은 데이터베이스에 저장된 테이블에서 그 고유번호보다 큰 번호를 가지는 고객정보를 구조체를 통해 반환한다.
클라이언트는 대화형 모드를 설정하면서 고유번호를 보내며 대화 주도권은 서버에 넘긴다. 서버는 조건을 만족하는 데이터베이스의 모든 데이터를 커서를 통해 읽어서 클라이언트로 보낸다. 클라이언트는 TPEVSVCSUCC를 통해 이상없이 모든 데이터를 읽어왔다는 것을 확인할 수 있다.
공통 프로그램
프로그램 파일 | 설명 |
---|---|
demo.s | 구조체를 정의한 파일이다. |
sample.m | Tmax 환경설정 파일이다. |
mktable.sql | 테이블 생성 스크립트이다. |
sel.sql | 테이블 및 데이터 출력 스크립트이다. |
클라이언트 프로그램
프로그램 파일 | 설명 |
---|---|
conv_cli.c | 클라이언트 프로그램이다. |
서버 프로그램
프로그램 파일 | 설명 |
---|---|
convsvc.pc | 서버 프로그램이다. |
Makefile | Tmax에서 제공되는 Makefile을 수정해야 한다. |
클라이언트 프로그램
기능 | 설명 |
---|---|
Tmax 연결 | 기본 연결 |
버퍼 유형 | 보낼 때 STRING, 받을 때 STRUCT |
통신 유형 | 대화형 통신TRUCT |
서버 프로그램
기능 | 설명 |
---|---|
서비스 | MULTI |
데이터베이스 연결 | Oracle 사용 |
다음은 대화형 통신에서 사용하는 구조체 버퍼이다.
<demo.s>
struct sel_o { char seqno[10]; char corpno[10]; char compdate[8]; int totmon; float guarat; float guamon; } ;
다음은 Tmax 환경 파일의 예제이다.
<sample.m>
* DOMAIN resrc SHMKEY = 77990, MAXUSER = 256 *NODE tmax TMAXDIR = “/home/tmax”, APPDIR = “/home/tmax/appbin”, PATHDIR =“/home/tmax/path” * SVRGROUP svg1 NODENAME = tmax, DBNAME = ORACLE, OPENINFO = “ORACLE_XA+Acc=P/scott/tiger+SesTm=60”, TMSNAME = svg1_tms *SERVER convsvc SVGNAME = svg1, CONV = Y *SERVICE MULTI SVRNAME = convsvc
다음은 환경설정에 추가된 항목에 대한 설명이다.
항목 | 설명 |
---|---|
DBNAME | 사용하는 데이터베이스명을 정의한다. |
OPENINFO | Oracle 데이터베이스와 연동하기 위한 연결 정보를 설정한다. |
TMSNAME | 전역 트랜잭션 처리를 주재하는 프로세스명을 설정한다. |
CONV | 대화형 모드 서버를 지정한다. |
다음은 Oracle 테이블 생성 스크립트의 예제이다.
<mktable.sql>
sqlplus scott/tiger << EOF create table multi_sel ( seqno VARCHAR(10), corpno VARCHAR(10), compdate VARCHAR(8), totmon NUMERIC(38), guarat FLOAT, guamon FLOAT ); create unique index idx_tdb on multi_sel(seqno); EOF
다음은 Oracle 테이블 및 데이터 출력 스크립트의 예제이다.
<sel.sql >
sqlplus scott/tiger << EOF Desc multi_sel; select * from multi_sel; EOF
다음은 클라이언트 프로그램의 예제이다.
<conv_cli.c>
#include <stdio.h> #include <usrinc/atmi.h> #include "../sdl/demo.s" main(int argc, char *argv[]) { struct sel_o *rcvbuf; char *sndbuf; long sndlen, rcvlen, revent; int cd; if (argc != 2) { printf("Usage: client string\n"); exit(1); } /* tpstart()와 함께 Tmax에 연결함. */ if (tpstart((TPSTART_T *) NULL) == -1) { printf("tpstart failed\n"); exit(1); } if ((sndbuf = tpalloc("STRING", NULL, 12)) == NULL) { printf("tpalloc failed:sndbuf\n"); tpend(); exit(1); } if ((rcvbuf = (struct sel_o *)tpalloc("STRUCT", "sel_o", 0)) == NULL) { printf("tpalloc failed:rcvbuf\n"); tpfree(sndbuf); tpend(); exit(1); } strcpy(sndbuf, argv[1]); if ((cd = tpconnect ("MULTI", sndbuf, 0, TPRECVONLY)) == -1){ printf("tpconnect failed:CONVER service, tperrno=%d\n", tperrno); tpfree(sndbuf); tpfree((char *)rcvbuf); tpend(); exit(1); } /* 대화형 통신 연결, 대화 주도권은 서버 측에 넘김 */ printf("tpconnect SUCESS \"MULTI\" service\n"); while ( 1 ) { /* 다중 데이터 수신. */ printf("tprecv strat\n"); if( tprecv(cd, (char **)&rcvbuf, &rcvlen, TPNOTIME, &revent) < 0 ) { /* 서버에서 tpreturn()으로 끝냈다면 */ if (revent == TPEV_SVCSUCC){ printf("all is completed\n"); break; } printf("tprecv failed, tperrno=%s, revent=%x\n", tpstrerror(tperrno), revent ); tpfree(sndbuf); tpfree((char *)rcvbuf); tpend(); exit(1); } printf("seqno = %s\t\t corpno =%s\n", rcvbuf->seqno, rcvbuf->corpno); printf("compdate = %s\t\t totmon =%d\n", rcvbuf->compdate, rcvbuf->totmon); printf("guarat = %f\t\t guamon =%f\n\n\n", rcvbuf->guarat, rcvbuf->guamon) ; } tpfree(sndbuf); tpfree((char *)rcvbuf); tpend(); printf("FINISH\n"); }
다음은 서버 프로그램의 예제이다.
<convsvc.pc>
#include <stdio.h> #include <string.h> #include <usrinc/atmi.h> #include “../sdl/demo.s” EXEC SQL begin declare section; /* Oracle 전역 변수 선언 */ char seq[10]; struct sel_o *sndbuf; EXEC SQL end declare section; EXEC SQL include sqlca; MULTI(TPSVCINFO *msg) { int i, cd; long sndlen, revent; memset(seq, 0, 10); strcpy(seq, msg->data); if ((sndbuf = (struct sel_o *) tpalloc (“STRUCT”, “sel_o”, 0)) == NULL) { printf(“tpalloc failed:\n”); tpreturn (TPFAIL, -1, NULL, 0, TPNOFLAGS); } /* 다량 데이터 위해 커서 선언 */ EXEC SQL declare democursor cursor for select * from corp where seqno > :seq; EXEC SQL open democursor; EXEC SQL whenever not found goto end_of_fetch; if (sqlca.sqlcode != 0){ printf(“oracle sqlerror=%s”, sqlca.sqlerrm.sqlerrmc); tpreturn (TPFAIL, sqlca.sqlcode, NULL, 0, TPNOFLAGS); } /* Oracle 에러가 없는 동안 데이터 전송 */ while ( sqlca.sqlcode == 0 ){ EXEC SQL fetch democursor into :sndbuf; if (tpsend (msg->cd, (char *)sndbuf, 0, TPNOTIME, &revent) == -1){ printf(“tpsend failed, tperrno=%d, revent=%x\n”, tperrno, revent ) ; tpfree ((char *)sndbuf); tpreturn (TPFAIL, -1, NULL, 0, TPNOFLAGS); } } tpreturn (TPFAIL, sqlca.sqlcode, NULL, 0, TPNOFLAGS); end_of_fetch: exec sql close democursor; printf(“tpreturn before”); tpreturn (TPSUCCESS, 0, NULL, 0, TPNOFLAGS); }
전역 트랜잭션(Global Transaction Processing)이란 하나 이상의 자원 관리자(데이터베이스)와 하나 이상의 물리적인 사이트가 하나의 논리적인 단위로 참여하는 트랜잭션이다. Tmax 시스템에서는 모든 트랜잭션을 일단 전역 트랜잭션으로 간주하며, 데이터의 무결성을 위해 2PC(2 Phase Commit)를 사용한다.
클라이언트는 사용자의 입력을 받아 구조체 버퍼를 통해 고유번호와 데이터를 보내며 서버는 해당 고유번호의 데이터를 업데이트하고 이 데이터로 다른 데이터베이스를 사용하는 서비스를 호출하여 테이블에 추가한다. 클라이언트는 이 모든 과정을 하나의 트랜잭션으로 지정하여 에러가 발생했을 경우 2개의 데이터베이스를 동시에 Rollback할 수 있도록 한다.
공통 프로그램
프로그램 파일 | 설명 |
---|---|
demo.s | 구조체 버퍼 설정 파일이다. |
sample.m | Tmax 환경설정 파일이다. |
mktable.sql | 데이터베이스에 테이블로 생성하는 SQL 스크립트이다. |
클라이언트 프로그램
프로그램 파일 | 설명 |
---|---|
client.c | 클라이언트 프로그램이다. |
서버 프로그램
프로그램 파일 | 설명 |
---|---|
update.pc | 데이터베이스에 업데이트하는 서버 프로그램이다. |
insert.pc | 데이터베이스에 INSERT하는 서버 프로그램이다. |
Makefile | Tmax에서 제공되는 Makefile을 수정해야 한다. |
클라이언트 부분
기능 | 설명 |
---|---|
Tmax 접속 | 기본 접속 |
버퍼 유형 | STRUCT |
통신 유형 | tpcall()에 의한 동기 통신 |
트랜잭션 처리 | 클라이언트에서 트랜잭션 범위 지정 |
서버 부분
기능 | 설명 |
---|---|
서버 프로그램 | 서로 다른 데이터베이스를 사용하는 2개의 서버 프로그램 |
서비스 | UPDATE, INSERT |
데이터베이스 연결 | 2종류의 Oracle 데이터베이스 |
다음은 전역 트랜잭션에서 사용하는 구조체 버퍼이다.
<demo.s>
struct input { int account_id; int branch_id; char phone[15]; char address[61]; };
다음은 Tmax 환경 파일의 예제이다.
<sample.m>
*DOMAIN res SHMKEY=88000, MINCLH=1, MAXCLH=5, TPORTNO=8880, BLOCKTIME=60 *NODE tmax1 TMAXDIR = "/user/ tmax ", APPDIR = "/user/ tmax /appbin", PATHDIR = "/user/ tmax /path", TLOGDIR = "/user/ tmax /log/tlog", ULOGDIR="/user/ tmax /log/ulog", SLOGDIR="/user/ tmax /log/slog" tmax2 TMAXDIR = "/user/ tmax ", APPDIR = "/user/ tmax /appbin", PATHDIR = "/user/ tmax /path", TLOGDIR = "/user/ tmax /log/tlog", ULOGDIR="/user/ tmax /log/ulog", SLOGDIR="/user/ tmax /log/slog" *SVRGROUP svg1 NODENAME = tmax1, DBNAME = ORACLE, OPENINFO = "ORACLE_XA+Acc=P/scott/tiger+SesTm=60", TMSNAME = svg1_tms svg2 NODENAME = tmax2, DBNAME = ORACLE, OPENINFO = "ORACLE_XA+Acc=P/scott/tiger+SesTm=60", TMSNAME = svg2_tms *SERVER update SVGNAME=svg1 insert SVGNAME=svg2 *SERVICE UPDATE SVRNAME=update INSERT SVRNAME=insert
다음은 Oracle 테이블 생성 스크립트의 예제이다.
<mktable.sql>
sqlplus scott/tiger << EOF drop table ACCOUNT; create table ACCOUNT ( ACCOUNT_ID integer, BRANCH_ID integer not null, SSN char(13) not null, BALANCE number, ACCT_TYPE char(1), LAST_NAME char(21), FIRST_NAME char(21), MID_INIT char(1), PHONE char(15), ADDRESS char(61), CONSTRAINT ACCOUNT_PK PRIMARY KEY(ACCOUNT_ID) ); quit EOF
다음은 클라이언트 프로그램 예제이다.
<client.c >
#include <stdio.h> #include <usrinc/atmi.h> #include "../sdl/demo.s" #define TEMP_PHONE "6283-2114" #define TEMP_ADDRESS "Korea" int main(int argc, char *argv[]) { struct input *sndbuf; char *rcvbuf; int acnt_id, n, timeout; long len; if (argc != 2) { fprintf(stderr, "Usage:%s account_id \n", argv[0]); exit(1); } acnt_id = atoi(argv[1]); timeout = 5; n = tmaxreadenv("tmax.env", "tmax"); if (n < 0) { fprintf(stderr, "tmaxreadenv fail! tperrno = %d\n", tperrno); exit(1); } n = tpstart((TPSTART_T *)NULL); if (n < 0) { fprintf(stderr, "tpstart fail! tperrno = %s\n", tperrno); exit(1); } sndbuf = (struct input *)tpalloc("STRUCT", "input", sizeof(struct input)); if (sndbuf == NULL) { fprintf(stderr, "tpalloc fail: sndbuf tperrno = %d\n", tperrno); tpend(); exit(1); } rcvbuf = (char *)tpalloc("STRING", NULL, 0); if (rcvbuf == NULL) { fprintf(stderr, "tpalloc fail: rcvbuf tperrno = %d\n", tperrno); tpend(); exit(1); } sndbuf->account_id = acnt_id; sndbuf->branch_id = acnt_id; strcpy(sndbuf ->phone, TEMP_PHONE); strcpy(sndbuf ->address, TEMP_ADDRESS); tx_set_transaction_timeout(timeout); n = tx_begin(); if (n < 0) fprintf(stderr, "tx begin fail! tperrno = %d\n", tperrno); n = tpcall("UPDATE", (char *)sndbuf, sizeof(struct input), (char **)&rcvbuf, (long *)&len, TPNOFLAGS); if (n < 0) { fprintf(stderr, "tpcall fail! tperrno = %d\n", tperrno); tpend(); exit(1); } n = tx_commit(); if (n < 0) { fprintf(stderr, "tx commit fail! tx error = %d \n", n); tx_rollback(); tpend(); exit(1); } printf("rtn msg = %s\n", rcvbuf); tpfree((char *)sndbuf); tpfree((char *)rcvbuf); tpend(); }
다음은 데이터베이스에 업데이트하는 서버 프로그램의 예제이다.
<update.pc>
#include <stdio.h> #include <ctype.h> #include <usrinc/atmi.h> #include <usrinc/sdl.h> #include "../sdl/demo.s" #define OKMSG "YOU COMPLETE THE TRANSACTION" EXEC SQL include sqlca.h; EXEC SQL BEGIN DECLARE SECTION; int account_id; int branch_id; char ssn[15]; char phone[15]; char address[61]; EXEC SQL END DECLARE SECTION; UPDATE(TPSVCINFO *msg) { struct input *rcvbuf; int ret; long acnt_id, rcvlen; char *send; rcvbuf = (struct input *)(msg->data); send = (char *)tpalloc("STRING", NULL, 0); if (send == NULL) { fprintf(stderr, "tpalloc fail errno = %s\n", strerror(tperrno)); tpreturn(TPFAIL, 0, (char *)NULL, 0, 0); } account_id = rcvbuf->account_id; branch_id = rcvbuf->branch_id; strcpy(phone, rcvbuf->phone); strcpy(address, rcvbuf->address); strcpy(ssn, "1234567"); EXEC SQL UPDATE ACCOUNT SET BRANCH_ID = :branch_id, PHONE = :phone, ADDRESS = :address, SSN = :ssn WHERE ACCOUNT_ID = :account_id; if (sqlca.sqlcode != 0 && sqlca.sqlcode != 1403 ) { fprintf(stderr, "update failed sqlcode = %d\n", sqlca.sqlcode); tpreturn(TPFAIL, -1, (char *)NULL, 0, 0); } rcvbuf->account_id++; ret = tpcall("INSERT", (char *)rcvbuf, 0, (char **)&send, (long *)&rcvlen, TPNOFLAGS); if (ret < 0) { fprintf(stderr, "tpcall fail tperrno = %d\n", tperrno); tpreturn(TPFAIL, -1, (char *)NULL, 0, 0); } strcpy(send, OKMSG); tpreturn(TPSUCCESS, 1, (char *)send, strlen(send), TPNOFLAGS); }
다음은 데이터베이스에 INSERT하는 서버 프로그램의 예제이다.
<insert.pc>
#include <stdio.h> #include <ctype.h> #include <usrinc/atmi.h> #include <usrinc/sdl.h> #include "../sdl/demo.s" #define OKMSG "YOU COMPLETE THE TRANSACTION" EXEC SQL include sqlca.h; EXEC SQL BEGIN DECLARE SECTION; int account_id; int branch_id; char ssn[15]; char phone[15]; char address[61]; EXEC SQL END DECLARE SECTION; INSERT(msg) TPSVCINFO *msg; { struct input *rcvbuf; int ret; long acnt_id; char *send; rcvbuf = (struct input *)(msg->data); send = (char *)tpalloc("STRING", NULL, 0); if (send == NULL) { fprintf(stderr, "tpalloc fail errno = %s\n", tpstrerror(tperrno)); tpreturn(TPFAIL, 0, (char *)NULL, 0, TPNOFLAGS); } account_id = rcvbuf->account_id; branch_id = rcvbuf->branch_id; strcpy(phone, rcvbuf->phone); strcpy(address, rcvbuf->address); strcpy(ssn, "1234567"); /* Declare && Open Cursor for Fetch */ EXEC SQL INSERT INTO ACCOUNT ( ACCOUNT_ID, BRANCH_ID, SSN, PHONE, ADDRESS ) VALUES ( :account_id, :branch_id, :ssn, :phone, :address); if (sqlca.sqlcode != 0 && sqlca.sqlcode != 1403 ) { printf("insert failed sqlcode = %d\n", sqlca.sqlcode); tpreturn(TPFAIL, -1, (char *)NULL, 0, TPNOFLAGS); } strcpy(send, OKMSG); tpreturn(TPSUCCESS, 1, (char *)send, strlen(send), TPNOFLAGS); }
대표적인 데이터베이스인 Oracle과 Informix를 사용하는 몇 가지 예제를 제시한다.
클라이언트는 사용자의 입력을 받아 구조체 버퍼에 넣어 서비스를 호출하며 서버는 이를 받아 해당 테이블에 추가한다. 클라이언트는 트랜잭션을 지정하여 에러가 발생하였을 경우 Rollback할 수 있도록 한다.
공통 프로그램
프로그램 파일 | 설명 |
---|---|
demo.s | 구조체 버퍼 설정 파일이다. |
sample.m | Tmax 환경설정 파일이다. |
mktable.sql | 데이터베이스 테이블을 생성하는 SQL 스크립트이다. |
sel.sql | 데이터베이스 테이블 내용을 출력하는 SQL 스크립트이다. |
클라이언트 프로그램
프로그램 파일 | 설명 |
---|---|
oins_cli.c | 클라이언트 프로그램이다. |
서버 프로그램
프로그램 파일 | 설명 |
---|---|
oinssvc.pc | 서비스 프로그램의 Oracle 소스이다. |
Makefile | Tmax에서 제공되는 Makefile을 수정해야 한다. |
클라이언트 프로그램
기능 | 설명 |
---|---|
Tmax 접속 | 기본 접속 |
버퍼 유형 | STRUCT |
통신 유형 | tpcall()에 의한 동기 통신 |
트랜잭션 처리 | 클라이언트에서 트랜잭션 범위 지정 |
서버 프로그램
구분 | 설명 |
---|---|
서비스 | ORAINS |
데이터베이스 연결 | Oracle 데이터베이스 |
다음은 구조체 버퍼의 예제이다.
<demo.s>
struct ktran { int no; char name[20]; };
다음은 Tmax 환경 파일의 예제이다.
<sample.m>
*DOMAIN resrc SHMKEY = 77990, MAXUSER = 256 *NODE tmax TMAXDIR = /home/tmax, APPDIR = /home/tmax/appbin, PATHDIR = /home/tmax/path *SVRGROUP svg1 NODENAME = tmax, DBNAME = ORACLE, OPENINFO = “Oracle_XA+Acc=P/scott/tiger+SesTm=60”, TMSNAME = svg1_tms *SERVER oinssvc SVGNAME = svg1, MIN = 1, MAX = 5 *SERVICE ORAINS SVRNAME = oinssvc
다음은 환경설정에 추가된 항목에 대한 설명이다.
항목 | 설명 |
---|---|
DBNAME | 사용하는 데이터베이스를 정의한다. |
OPENINFO | Oracle 데이터베이스 연결 정보를 설정하는 항목으로 Oracle 데이터베이스인 경우 CLOSEINFO는 지정하지 않아도 된다. tpsvrinfo()에서 호출한다. |
TMSNAME | 트랜잭션 처리를 주재하는 프로세스명을 지정하는 항목으로 OPENINFO 지정으로 인한 자동 트랜잭션을 처리한다. svg1에 속한 해당 서비스를 자동 트랜잭션 상태에서 처리한다. |
다음은 Oracle 테이블 생성 스크립트의 예제이다.
<mktable.sql>
sqlplus scott/tiger << EOF create table testdb1 ( no number(7), name char(30) ) ; EOF
다음은 Oracle 테이블 및 데이터 출력 스크립트의 예제이다.
<sel.sql>
sqlpus scott/tiger << EOF desc testdb1; select * from testdb1; select count (*) from testdb1; EOF
다음은 클라이언트 프로그램의 예제이다.
<oins_cli.c>
#include <stdio.h> #include <usrinc/atmi.h> #include “../sdl/demo.s” main(int argc, char *argv[]) { struct ktran *sndbuf, *rcvbuf; long sndlen, rcvlen; int cd; if (argc != 3) { printf(“Usage: client no name\n”); exit(1); } printf(“tpstart-start \n”); if(tpstart ((TPSTART_T *) NULL) == -1) { printf(“Tpstart failed\n”); exit(1); } printf(“tpstart-ok \n”); if((sndbuf=(struct ktran *) tpalloc("STRUCT","ktran",0))==NULL) { printf(“tpalloc failed:sndbuf, tperrno=%d\n”, tperrno); tpend(); exit(1) ; } if((rcvbuf = (struct ktran *) tpalloc("STRUCT", "ktran", 0))== NULL) { printf(“tpalloc failed:rcvbuf, tperrno=%d\n”, tperrno); tpfree((char *)sndbuf); tpend(); exit(1); } sndbuf->no = atoi(argv[1]); strcpy(sndbuf->name, argv[2]); printf(“tpcall-start \n”); tx_begin(); if(tpcall("ORAINS",(char *)sndbuf,0,(char **)&rcvbuf,&rcvlen,TPNOFLAGS)==-1){ printf(“tpcall failed:ORA service, tperrno=%d”, tperrno); printf(“sql code=%d\n”, tpurcode); tx_rollback(); tpfree ((char *)sndbuf); tpfree ((char *)rcvbuf); tpend(); exit(1); } printf(“tpcall-success \n”); tx_commit(); tpfree ((char *)sndbuf); tpfree ((char *)rcvbuf); tpend(); }
다음은 서버 프로그램의 예제이다.
<oinssvc.pc>
#include <stdio.h> #include <usrinc/atmi.h> #include “../sdl/demo.s” EXEC SQL begin declare section; char name[20]; int no; EXEC SQL end declare section; EXEC SQL include sqlca; ORAINS(TPSVCINFO *msg) { struct ktran *stdata; stdata = (struct ktran *)msg->data; strcpy(name, stdata->name); no = stdata->no; printf(“Ora service started\n”); /* 데이터베이스에 삽입 */ EXEC SQL insert into testdb1(no, name) values(:no, :name); if (sqlca.sqlcode != 0){ printf(“oracle sqlerror=%s”,sqlca.sqlerrm.sqlerrmc); tpreturn (TPFAIL, sqlca.sqlcode, NULL, 0, TPNOFLAGS); } tpreturn (TPSUCCESS, sqlca.sqlcode, stdata, 0, TPNOFLAGS); }
클라이언트는 사용자의 입력을 받아 구조체 버퍼에 넣어 서비스를 호출하며 서버는 이에 해당하는 모든 데이터를 받아 구조체 배열을 사용하여 결과를 반환한다. 클라이언트는 트랜잭션을 지정하여 에러가 발생하였을 경우 Rollback할 수 있도록 한다.
공통 프로그램
구성 | 설명 |
---|---|
demo.s | 구조체 버퍼 설정 파일이다. |
sample.m | Tmax 시스템 환경 파일이다. |
mktable.sql | 데이터베이스에 테이블을 생성하는 SQL 스크립트이다. |
sel.sql | 데이터베이스 테이블 내용을 출력하는 SQL 스크립트이다. |
클라이언트 프로그램
구성 | 설명 |
---|---|
oins_cli.c | 클라이언트 프로그램이다. |
cdata.c | 클라이언트 사용 함수 모듈이다. |
서버 프로그램
구성 | 설명 |
---|---|
oselsvc.pc | 서비스 프로그램 Oracle 소스이다. |
Makefile | Tmax에서 제공되는 Makefile로 수정해야 한다. |
클라이언트 프로그램
기능 | 설명 |
---|---|
Tmax 접속 | 기본 접속 |
서비스 | ORASEL |
버퍼 유형 | STRUCT |
통신 유형 | tpcall()에 의한 동기 통신 |
트랜잭션 처리 | 클라이언트에서 트랜잭션 범위 지정 |
서버 프로그램
기능 | 설명 |
---|---|
서비스 | ORASEL |
데이터베이스 연결 | Oracle 데이터베이스 |
버퍼사용 | 필요에 의해 버퍼 크기 재조정 |
다음은 구조체 버퍼의 예제이다.
<demo.s>
struct stru_his{ long ACCOUNT_ID ; long TELLER_ID ; long BRANCH_ID ; long AMOUNT ; } ;
다음은 Tmax 환경 파일의 예제이다.
<sample.m>
*DOMAIN resrc SHMKEY = 77990, MAXUSER = 256 *NODE tmax TMAXDIR =“/home/tmax”, APPDIR =“/home/tmax/appbin”, PATHDIR =“/home/tmax/path” *SVRGROUP svg1 NODENAME = tmax, DBNAME = ORACLE, OPENINFO = “Oracle_XA+Acc=P/scott/tiger+SesTm=600”, TMSNAME = svg1_tms *SERVER oselsvc SVGNAME = svg1, MIN = 1, MAX = 5 *SERVICE ORASEL SVRNAME = oselsvc
다음은 환경설정에 추가된 항목에 대한 설명이다.
항목 | 설명 |
---|---|
DBNAME | 사용할 데이터베이스명을 설정한다. |
OPENINFO | Oracle 데이터베이스 연결 정보를 설정하는 항목으로 Oracle에서는 CLOSEINFO는 설정하지 않아도 된다. 사용가능한 옵션은 표 이후에 설명한다. |
TMSNAME | 트랜잭션 처리를 관리하는 프로세스명을 지정한다. |
AUTOTRAN | 해당 서비스를 처리할 때 자동으로 트랜잭션 상태로 처리한다. |
다음은 OPENINFO 항목에서 사용할 수 있는 옵션으로 LogDir과 DbgFl을 사용할 수 있다.
옵션 | 설명 |
---|---|
LogDir | LogDir을 지정하면 지정된 곳에 XA에 관련된 로그를 남길 수 있다. LogDir을 지정하지 않으면 $ORACLE_HOME/rdbms/log 또는 현재 디렉터리에 <xa_NULL날짜.trc> 파일이 생성된다. |
DbgFl | 몇 번째 단계의 디버그 flags를 설정할지를 결정한다. 기본적인 단계인 0x01 또는 OCI 단계인 0x04 등을 사용하면 된다. |
다음은 OPENINFO 항목의 옵션으로 LogDir과 DbgFl을 사용하는 예제이다.
OPENINFO=“Oracle_XA+Acc=P/계정/암호 +SesTm=60+LogDir=/tmp+DbgFl=0x01”
개발할 때에는 디버그 모드를 해제하고 사용해야만 나중에 디스크가 Full되는 상황을 피할 수 있다.
다음은 Oracle 테이블 작성 스크립트의 예제이다.
<mktable.sql>
sqlplus scott/tiger << EOF create table sel_his( account_id number(6), teller_id number(6), branch_id number(6), amount number(6) ); create unique index idx_tdb1 on sel_his(account_id); EOF
다음은 Oracle 테이블 및 데이터 출력 스크립트의 예제이다.
<sel.sql>
sqlplus scott/tiger << EOF desc sel_his; select * from sel_his; EOF
다음은 클라이언트 프로그램의 예제이다.
<oins_cli.c>
#include <stdio.h> #include <usrinc/atmi.h> #include <usrinc/tx.h> #include “../sdl/demo.s” #define NARRAY 10 #define NOTFOUND 1403 main(int argc,char *argv[]) { struct stru_his *transf; int i, j; long urcode, nrecv, narray = NARRAY; long account_id, teller_id, branch_id, amount; if (argc != 2) { fprintf(stderr,“Usage:$%s ACOUNT_ID !\n”, argv[0]); exit(0); } if (tpstart((TPSTART_T *) NULL) == -1) { /* Tmax에 접속 */ fprintf(stderr,“TPSTART_T(tpinfo) failed -> %s!\n”, tpstrerror(tperrno)) ; exit(1) ; } /* c structure 구조로 버퍼 생성 */ transf = (struct stru_his *) tpalloc(“STRUCT”, “stru_his”,0); if (transf == (struct stru_his *)NULL) { fprintf(stderr,“Tpalloc failed->%s!\n”, tpstrerror(tperrno)) ; tpend(); exit(1); } memset(transf, 0x00, sizeof(struct stru_his)); account_id = atoi(argv[1]); transf->ACCOUNT_ID = account_id; /* 트랜잭션 타임아웃 설정 */ tx_set_transaction_timeout(30); /* 글로벌 트랜잭션 시작 */ if (tx_begin() < 0) { fprintf(stderr, “tx_begin() failed ->%s!\n”, tpstrerror(tperrno)); tpfree((char*)transf); tpend(); exit(0) ; } if (tpcall(“ORASEL”,(char *)transf, 0, (char **)&transf, &nrecv, TPNOFLAGS)== -1){ /* 동기 통신으로 “ORASEL” 서비스 요청 */ fprintf(stderr,“Tpcall(SELECT...)error->%s ! ”, tpstrerror(tperrno)) ; tpfree((char *)transf); /* 실패시 트랜잭션 취소 */ tx_rollback(); tpend(); exit(0) ; } /* 성공시 트랜잭션 Commit */ if (tx_commit() == -1) { fprintf(stderr, “tx_commit() failed ->%s!\n”, tpstrerror(tperrno)) ; tpfree((char *)transf); tpend(); exit(0) ; } /* 받아온 데이터는 구조체의 배열이다. */ for (j =0 ; j < tpurcode ; j++) { /* Oracle에서 셀렉트한 데이터 결과를 프린트 */ if (j == 0) printf(“%-12s%-10s%-10s%-10s\n”, “ACCOUNT_ID”,“TELLER_ID”, “BRANCH_ID”, “AMOUNT”); account_id=transf[j].ACCOUNT_ID; teller_id=transf[j].TELLER_ID; branch_id=(*(transf+j)).BRANCH_ID; amount=transf[j].AMOUNT; printf(“%-12d %-10d %-10d %-10d\n”, account_id, teller_id,branch_id, amount); } /* 셀렉트한 데이터가 없거나 끝이라면 */ if (urcode == NOTFOUND) { printf(“No records selected!\n”); tpfree((char *)transf); tpend(); return 0; } tpfree((char *)transf); tpend(); }
다음은 서버 프로그램의 예제이다.
<oselsvc.pc>
#include <stdio.h> #include <usrinc/atmi.h> #include “../sdl/demo.s” #define NARRAY 10 #define TOOMANY 2112 #define NOTFOUND 1403 EXEC SQL include sqlca.h; EXEC SQL begin declare section; long key, rowno= NARRAY; long account_id[NARRAY],teller_id[NARRAY], branch_id[NARRAY], amount[NARRAY] ; EXEC SQL end declare section; ORASEL(TPSVCINFO *msg) { struct stru_his *transf; int i , lastno; transf=(struct stru_his *) msg->data; /* msg 버퍼의 내용을 프로그램 변수에 전달. */ key = transf->ACCOUNT_ID; /* transf 버퍼의 크기를 재조정 */ if((transf=(struct stru_his *) tprealloc((char*)transf, sizeof(struct stru_his) * NARRAY ))==(struct stru_his*)NULL){ fprintf(stderr, “tprealloc error ->%s\n”, tpstrerror(tperrno)); tpreturn(TPFAIL, tperrno, NULL, 0, TPNOFLAGS); } EXEC SQL select account_id, teller_id, branch_id, amount into :account_id, :teller_id, :branch_id, :amount from sel_his where account_id > :key /* account_id가 client에서 보낸 key값 보다 큰 것을 */ order by account_id; /* global 변수에 넣어줌 */ /* sql error 체크 (셀렉트된 것이 없거나 너무 많은 것 제외.) */ if (sqlca.sqlcode!=0 && sqlca.sqlcode!=NOTFOUND && sqlca.sqlcode!=TOOMANY) { fprintf(stderr,“SQL ERROR ->NO(%d):%s\n”, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc) ; tpreturn(TPFAIL, sqlca.sqlcode, NULL, 0, TPNOFLAGS); } /* access한 개수를 lastno에 넣어줌 */ lastno = sqlca.sqlerrd[2]; /* 셀렉트된 데이터가 너무 많음 */ if (sqlca.sqlcode == TOOMANY) lastno =rowno; /* No records */ if (lastno == 0) transf->ACCOUNT_ID = 0; /* Oracle에서 셀렉트한 데이터를 전송할 버퍼에 넣어줌 */ for ( i = 0 ; i < lastno; i++) { transf[i].ACCOUNT_ID = account_id[i]; transf[i].TELLER_ID = teller_id[i]; transf[i].BRANCH_ID = branch_id[i]; transf[i].AMOUNT = amount[i]; } tpreturn(TPSUCCESS, lastno, transf, i * sizeof(struct stru_his), TPNOFLAGS ); }
클라이언트는 사용자의 입력을 받아 구조체 버퍼에 넣어 서비스를 호출하며 서버는 이를 받아 해당 테이블에 추가한다. 클라이언트는 트랜잭션을 지정하여 에러가 발생한 경우 Rollback한다.
Informix 애플리케이션을 컴파일하기 전 다음 사항을 먼저 확인한다.
UNIX 환경을 확인한다( .profile,.login, .cshrc ).
다음과 같이 설정한다.
INFORMIXDIR=/home/informix INFORMIXSERVER=tmax ONCONFIG=onconfig PATH=$INFORMIXDIR/bin: … LD_LIBRARY_PATH=/home/informix/lib:/home/informix/lib/esql: …
Makefile을 확인한다.
다음 오퍼레이션과 설정을 확인한다.
# Server esql makefile TARGET = <target filename> APOBJS = $(TARGET).o SDLFILE = info.s LIBS = -lsvr -linfs # solaris의 경우 –lnsl –lsocket 추가 OBJS = $(APOBJS) $(SDLOBJ) $(SVCTOBJ) SDLOBJ = ${SDLFILE:.s=_sdl.o} SDLC = ${SDLFILE:.s=_sdl.c} SVCTOBJ = $(TARGET)_svctab.o CFLAGS =-O -I$(INFORMIXDIR)/incl/esql -I$(TMAXDIR) # Solaris 32bit, Compaq, Linux: CFLAGS = -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR) # Solaris 64bit: CFLAGS = -xarch=v9 -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR) # HP 32bit: CFLAGS = -Ae -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR) # HP 64bit: CFLAGS = -Ae +DA2.0W +DD64 +DS2.0 -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR) # IBM 32bit: CFLAGS = -q32 –brtl -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR) # IBM 64bit: CFLAGS = -q64 –brtl -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR) INFLIBD = $(INFORMIXDIR)/lib/esql INFLIBDD = $(INFORMIXDIR)/lib INFLIBS = -lifsql -lifasf -lifgen -lifos -lifgls -lm -ldl -lcrypt $(INFORMIXDIR)/lib/esql/ checkapi.o -lifglx -lifxa APPDIR = $(TMAXDIR)/appbin SVCTDIR = $(TMAXDIR)/svct TMAXLIBDIR = $(TMAXDIR)/lib # .SUFFIXES : .ec .s .c .o .ec.c : esql -e $*.ec # # server compile # all: $(TARGET) $(TARGET):$(OBJS) $(CC) $(CFLAGS) -L$(TMAXLIBDIR) -L$(INFLIBD) -L$(INFLIBDD) -o $(TARGET) $(OBJS) $(LIBS) $(INFLIBS) mv $(TARGET) $(APPDIR)/. rm -f $(OBJS) $(APOBJS): $(TARGET).ec esql -e -I$(TMAXDIR)/usrinc $(TARGET).ec $(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) $(TARGET).lis
<TMS Makefile>
# TARGET = info_tms INFOLIBDIR = ${INFORMIXDIR}/lib INFOELIBDIR = ${INFORMIXDIR}/esql INFOLIBD = ${INFORMIXDIR}/lib/esql INFOLIBS = -lifsql -lifasf -lifgen -lifos -lifgls -lm -ldl -lcrypt /opt/informix/lib/esql/checkapi.o -lifglx -lifxa # solaris는 라이브러리에 –lnsl –lsocket –laio –lelf 추가 CFLAGS =-O -I$(INFORMIXDIR)/incl/esql -I$(TMAXDIR) # Solaris 32bit, Compaq, Linux: CFLAGS = -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR) # Solaris 64bit: CFLAGS = -xarch=v9 -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR) # HP 32bit: CFLAGS = -Ae -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR) # HP 64bit: CFLAGS = -Ae +DA2.0W +DD64 +DS2.0 -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR) # IBM 32bit: CFLAGS = -q32 –brtl -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR # IBM 64bit: CFLAGS = -q64 –brtl -O -I$(INFORMIXDIR)/incl/esql –I$(TMAXDIR TMAXLIBDIR = $(TMAXDIR)/lib TMAXLIBS = -ltms -linfs # CC = /opt/SUNWspro/bin/cc : solaris only $(TARGET): $(APOBJ) $(CC) $(CFLAGS) -o $(TARGET) -L$(TMAXLIBDIR) -L$(INFOLIBD) -L$(INFOLIBDIR) -L $(INFOELIBDIR) $(INFOLIBS) $(TMAXLIBS) mv $(TARGET) $(TMAXDIR)/appbin # clean: -rm -f *.o core $(TARGET)
공통 프로그램
프로그램 파일 | 설명 |
---|---|
demo.s | 구조체 버퍼 설정 파일이다. |
sample.m | Tmax 시스템 환경 파일이다. |
mkdb.sql | 데이터베이스 생성 SQL 스크립트로 XA 모드는 데이터베이스가 로깅 모드에서 생성될 때 지원한다. |
mktable.sql | 데이터베이스에 테이블을 생성하는 SQL 스크립트이다. |
sel.sql | 데이터베이스 테이블에 내용을 출력하는 SQL 스크립트이다. |
info.s | SDLFILE이다. |
클라이언트 프로그램
프로그램 파일 | 설명 |
---|---|
client.c | 클라이언트 프로그램이다. |
서버 프로그램
구성 | 설명 |
---|---|
tdbsvr.ec | 서버 프로그램이다. |
Makefile | Tmax에서 제공되는 Makefile을 수정한다. |
클라이언트 프로그램
기능 | 설명 |
---|---|
Tmax 접속 | 기본 접속 |
버퍼 유형 | STRUCT |
통신 유형 | tpcall()에 의한 동기 통신 |
트랜잭션 처리 | 클라이언트에서 트랜잭션 범위 지정 |
서버 프로그램
기능 | 설명 |
---|---|
서비스 | INSERT |
데이터베이스 연결 | Informix 데이터베이스 |
다음은 구조체 버퍼의 예제이다.
<demo.s>
struct info { char seq[8]; char data01[128]; char data02[128]; char data03[128]; };
다음은 Tmax 환경 파일의 예제이다.
<sample.m>
*DOMAIN resrc SHMKEY = 77990, MAXUSER = 256 *NODE tmax TMAXDIR =”/home/tmax”, A APPDIR =”/home/tmax/appbin”, PATHDIR =”/home/tmax/path” *SVRGROUP svg1 NODENAME = tmax, DBNAME = INFORMIX, OPENINFO = “stores7”, CLOSEINFO = “”, TMSNAME = info_tms *SERVER tdbsvr SVGNAME = svg1, MIN = 1, MAX = 5 *SERVICE INSERT SVRNAME = tdbsvr
다음은 환경 설정에 추가된 항목에 대한 설명이다.
항목 | 설명 |
---|---|
DBNAME | 사용할 데이터베이스명을 설정한다. |
OPENINFO, CLOSEINFO | Informix 데이터베이스 연결 및 해제를 위한 정보를 tpsvrinfo(), tpsvrdone()에서 호출한다. |
TMSNAME | 트랜잭션을 처리하는 프로세스명을 지정하는 항목으로 OPENINFO 지정으로 인한 자동 트랜잭션 처리 svg1에 속한 해당 서비스를 자동 트랜잭션 상태에서 처리한다. |
다음은 Informix 테이블 생성 스크립트의 예제이다.
<mktable.sql>
dbaccess << EOF create database stores7 with buffered log; grant connect to public; database stores7; drop table testdb1; create table testdb1 ( seq VARCHAR(8) , data01 VARCHAR(120) , data02 VARCHAR(120) , data03 VARCHAR(120) ) lock mode row; create unique index idx_tdb1 on testdb1(seq); EOF
다음은 Informix 테이블 및 데이터 출력 스크립트의 예제이다.
<sel.sql>
dbaccess << EOF database stores7; select * from testdb1; EOF
다음은 클라이언트 프로그램의 예제이다.
<client.c>
#include <stdio.h> #include <usrinc/atmi.h> #include <usrinc/tx.h> #include “info.s” main(int argc, char **argv) { struct info *transf; char data[256]; long nrecv; /* Tmax에 연결. */ if ((tpstart((TPSTART_T *)NULL) == -1) { fprintf(stderr, “tpstart(TPINFO...) failed ->%s!\n”, tpstrerror(tperrno)) ; exit(1) ; } /* 응용프로그램에서 사용할 버퍼 메모리 할당. */ if ((transf=(struct info *)tpalloc ("STRUCT","info",0))==(struct info *)NULL){ fprintf(stderr, “tpalloc(struct info, ...) failed ->%s!\n”, tpstrerror(tperrno)) ; tpend(); exit(1) ; } /* 전송할 데이터 필드를 채움. */ strcpy(transf->seq, “000001”); strcpy(transf->data01, “Hello”); strcpy(transf->data02, “World”); strcpy(transf->data03, “1234”); /* 트랜잭션 timeout 설정 * / tx_set_transaction_timeout (30); /* 트랜잭션 시작을 알림. */ if (tx_begin() < 0) { fprintf(stderr, “tx_begin() failed ->%s!\n”, tpstrerror(tperrno)) ; tpfree ((char *)transf); tpend( ); exit(0); } /* 서비스 호출 */ if (tpcall ("INSERT",(char*) transf,0,(char **)&transf,&nrecv,TPNOFLAGS)==-1) { fprintf(stderr,"tpcall(struct info, ...) failed ->%s!\n",tpstrerror(tperrno)) ; tx_rollback (); tpfree ((char *)transf), tpend(); exit(0); } /* 트랜잭션 성공. */ if (tx_commit () < 0) { fprintf(stderr, “tx_commit() failed ->%s!\n”, tpstrerror(tperrno)) ; tpfree ((char *)transf); tpend( ); exit(0); } tpfree ((char *)transf ); /* Tmax 연결을 끊음. */ tpend( ) ; }
다음은 서버 프로그램의 예제이다.
< tdbsvr.ec>
#include <stdio.h> #include <ctype.h> #include <usrinc/atmi.h> #include “info.s” EXEC SQL include sqlca.h; /* 서비스 명*/ INSERT(TPSVCINFO *msg) { /* 프로그램상의 버퍼 형식 선언. */ struct info *INFO; /* SQL문 내의 버퍼 형식 선언. */ EXEC SQL begin declare section; varchar seq[8],buf01[128],buf02[128],buf03[128]; EXEC SQL end declare section; /* 메시지 버퍼로부터 구조체형으로 데이터를 전달받는다. */ INFO = (struct info *)msg -> data; /* 구조체 형식으로 전달받은 데이터를 데이터베이스 버퍼로 복사. */ strcpy(seq, INFO->seq); strcpy(buf01, INFO->data01); strcpy(buf02, INFO->data02); strcpy(buf03, INFO->data03); /* SQL문의 insert 수행 */ EXEC SQL insert into testdb1 (seq,data01,data02,data03) values(:seq, :buf01, :buf02, :buf03); /* 에러가 발생한다면 */ if ( sqlca.sqlcode ! = 0) { /* Insert 실패를 알린다. */ printf(“SQL error => %d !” ,sqlca.sqlcode); tpreturn (TPFAIL, sqlca.sqlcode, NULL, 0, TPNOFLAGS); } /* Insert가 성공적으로 끝났을 때 */ tpreturn (TPSUCCESS, 0, NULL, 0, TPNOFLAGS); }
클라이언트는 사용자의 입력을 받아 구조체 버퍼에 넣어 서비스를 호출하며 서버는 이에 해당하는 모든 데이터를 받아 구조체 배열을 사용하여 결과를 반환한다. 클라이언트는 트랜잭션을 지정하여 에러가 발생하였을 경우 Rollback할 수 있도록 한다.
공통 프로그램
프로그램 파일 | 설명 |
---|---|
acct.s | SDLFILE이다. |
sample.m | Tmax 환경 파일이다. |
mkdb.sql | 데이터베이스를 생성하는 SQL 스크립트이다. |
mktables.sql | 데이터베이스에 테이블을 생성하는 SQL 스크립트이다. |
sel.sql | 데이터베이스 테이블에 내용을 출력하는 SQL 스크립트이다. |
클라이언트 프로그램
구성 | 설명 |
---|---|
client.c | 클라이언트 프로그램이다. |
cdate.c | client.c에서 사용된 함수 모듈이다. |
서버 프로그램
구성 | 설명 |
---|---|
sel_acct.ec | 서비스 프로그램 Informix 소스이다. |
Makefile | Tmax에서 제공되는 Makefile을 수정한다. |
클라이언트 프로그램
구분 | 설명 |
---|---|
Tmax 접속 | 기본 접속 |
버퍼 유형 | STRUCT |
통신 유형 | tpcall()에 의한 동기 통신 |
트랜잭션 처리 | 클라이언트에서 트랜잭션 범위 지정 |
서버 프로그램
구분 | 설명 |
---|---|
서비스 | SEL_ACCT |
데이터베이스 연결 | Informix 데이터베이스 |
버퍼 사용 | 필요에 의해 버퍼 크기 재조정 |
다음은 구조체 버퍼의 예제이다.
<acct.s>
struct stru_acct { int ACCOUNT_ID; char PHONE[20]; char ADDRESS[80]; };
다음은 Tmax 환경 파일의 예제이다.
<sample.m>
*DOMAIN resrc SHMKEY = 77990, MAXUSER = 256 *NODE tmax TMAXDIR =”/home/tmax”, APPDIR =”/home/tmax/appbin”, PATHDIR =”/home/tmax/path” *SVRGROUP svg1 NODENAME = tmax, DBNAME = INFORMIX, OPENINFO = “stores7”, CLOSEINFO = “”, TMSNAME = info_tms *SERVER SEL_ACCT SVGNAME = svg1, MIN = 1, MAX = 5 *SERVICE SEL_ACCT SVRNAME = sel_acct
다음은 환경 설정에 추가된 항목에 대한 설명이다.
항목 | 설명 |
---|---|
DBNAME | 사용할 데이터베이스를 설정한다. |
OPENINFO, CLOSEINFO | Informix 데이터베이스에 연결 및 해제를 위한 정보를 tpsvrinit(), tpsvrdone()에서 호출한다. |
TMSNAME | 트랜잭션을 처리하는 프로세스명을 지정하는 항목으로 OPENINFO 지정으로 인한 자동 트랜잭션을 처리한다. svg1에 속한 해당 서비스를 자동 트랜잭션 상태에서 처리한다. |
다음은 Informix 테이블 생성 스크립트의 예제이다.
<mkdb.sql>
dbaccess << EOF create database stores7 with buffered log; grant connect to public; database stores7; drop table ACCOUNT; create table ACCOUNT ( account_id INTEGER, phone VARCHAR(20), address VARCHAR(80) ) lock mode row; create unique index idx_tdb1 on ACCOUNT(account_id); EOF
다음은 Informix 테이블 및 데이터 출력 스크립트의 예제이다.
<sel.sql>
dbaccess << EOF database stores7; select * from ACCOUNT; EOF
다음은 클라이언트 프로그램의 예제이다.
<client.c>
#include <stdio.h> #include <time.h> #include <usrinc/atmi.h> #include <usrinc/tx.h> #include “acct.s” #define NOTFOUND 1403 void htime(char *, int *); main(int argc, char *argv[ ]) { struct stru_acct *transf; float tps; int i, j, loop, cnt_data = 0, sec1, sec2; long urcode, nrecv, narray; char ts[30], te[30], phone[20], address[80]; int account_id, key; if(argc != 2) { fprintf(stderr,“Usage:$%sLOOP (NARRAY = 30) !\n”, argv[0]); exit(0) ; } /*user가 원하는 수행 횟수만큼 루프를 돈다.*/ loop = atoi(argv[1]); /* Tmax에 접속 */ if (tpstart((TPSTART_T *)NULL) == -1) { fprintf(stderr, “tpstart(tpinfo) failed ->%s!\n”, tpstrerror(tperrno)); exit(1) ; } /* sec1 = 시작시간 */ htime(ts,&sec1); key=0; /* message 버퍼 할당 */ for( i = 0; i < loop; i++) { if ((transf=(struct stru_acct *)tpalloc("STRUCT","stru_acct",0)) ==(struct stru_acct *)NULL) { fprintf(stderr,“Tpalloc(STRUCT.. )failed->%s!\n” , tpstrerror(tperrno)) ; tpend(); exit(1); } transf -> ACCOUNT_ID = key; /* time-out value= 30 */ tx_set_transaction_timeout(30) ; if (tx_begin() < 0) { /* 트랜잭션 시작 */ fprintf(stderr, “tx_begin() failed ->%s!\n”, tpstrerror(tperrno)) ; tpfree((char*)transf); tpend(); exit(0); } /* select service 호출 */ if (tpcall(“SEL_ACCT”, (char *)transf, 0, (char **)&transf, &nrecv, TPNOFLAGS)== -1) { /* service error : message buffer free & 트랜잭션 취소 & 접속 끊음 */ fprintf(stderr,“Tpcall(SELECT...)error->%s! ” , tpstrerror(tperrno)) ; tpfree ((char *)transf); tx_rollback ( ) ; tpend( ) ; exit ( 1 ) ; } urcode = tpurcode; /*성공적인 서비스 완결 : 트랜잭션 결과로 실제 리소스 변화시킴*/ if (tx_commit() < 0 ) { fprintf(stderr, “tx_commit() failed ->%s!\n”, tpstrerror(tperrno)) ; tpfree((char *)transf); tpend(); exit(0); } /*데이터가 선택된 경우*/ if ( urcode != NOTFOUND) { narray =urcode; /* select한 데이터의 마지막 Record */ key=transf[narray-1].ACCOUNT_ID; /* selsct한 개수 만큼 결과를 user에게 출력 */ for ( j = 0 ; j < narray ; j++ ) { if ( j == 0) printf(“%-10s%-14s%s\n”, “ACCOUNT_ID”, “PHONE”,“ADDRESS”) ; account_id = transf[j].ACCOUNT_ID; strcpy(phone, transf[j].PHONE); strcpy(address, transf[j].ADDRESS); printf(“%-10d %-14s %s\n”, account_id, phone, address); }/* for2 end */ /* 전체 결과 개수 증가 */ cnt_data += j; /* message buffer free */ tpfree ((char *)transf); if(urcode == NOTFOUND) { printf(“No records selected!\n”); break ; } }/* for1 end */ /* message buffer free */ tpfree ((char *)transf); /* Tmax 연결을 끊음. */ tpend (); /* sec2 = 끝 시간 */ htime(te,&sec2); /* 데이터 하나당 처리시간 계산. */ printf(“TOT.COUNT = %d\n”, cnt_data); printf(“Start time = %s\n”, ts); printf(“End time = %s\n”, te); if ((sec2-sec1) ! = 0) tps = (float) cnt_data / (sec2 - sec1); else tps = cnt_data; printf(“Interval = %d secs ==> %10.2f T/S\n”, sec2-sec1,tps); } htime(char *cdate, int *sec) { long time(), timef, pt; char ct[20], *ap; struct tm *localtime(), *tmp; pt = time(&timef); *sec = pt; tmp = localtime(&timef); ap = asctime(tmp); sscanf(ap, “%*s%*s%*s%s”,ct); sprintf( cdate, “%02d. %02d. %02d %s”, tmp->tm_year, ++tmp->tm_mon, tmp->tm_mday,ct); }
다음은 서버 프로그램의 예제이다.
<sel_acct.pc>
#include <stdio.h> #include <usrinc/atmi.h> #include <usrinc/tx.h> #include “acct.s” #define NFETCH 5 #define NOTFOUND 100 EXEC SQL include sqlca.h; EXEC SQL begin declare section; long account_id, key; varchar phone[20], address[80]; EXEC SQL end declare section; SEL_ACCT(TPSVCINFO *msg) { int i , j , nfetch; int return_code; struct stru_acct *ACCT_V; /*클라이언트 데이터를 받는다. */ ACCT_V = (struct stru_acct *) msg->data; /* select원하는 account id 값을 key에 옮김. */ key = ACCT_V->ACCOUNT_ID; /* 클라이언트 버퍼 사이즈 재할당*/ if ((ACCT_V = (struct stru_acct *)tprealloc((char *)ACCT_V, sizeof(struct stru_acct)*NFETCH )) == (struct stru_acct *)NULL) { fprintf(stderr, “tprealloc error =%s\n”, tpstrerror(tperrno)); tpreturn (TPFAIL, tperrno, NULL, 0, TPNOFLAGS); } /*버퍼 초기화*/ ACCT_V->ACCOUNT_ID = 0; strcpy(ACCT_V->PHONE,“ ” ) ; strcpy(ACCT_V->ADDRESS,“ ” ) ; /* ACCOUNT 테이블로부터 phone, address 필드를 뽑음 */ EXEC SQL declare CUR_1 cursor for select account_id,phone,address into :account_id, :pfone, :address from ACCOUNT where account_id > :key;/* 필드키보다 account id가 클 때 */ /* cursor open */ EXEC SQL open CUR_1; /* cursor open error */ if (sqlca.sqlcode ! = 0) { printf(“open cursor error !\n”); tpreturn(TPFAIL, sqlca.sqlcode, NULL, 0, TPNOFLAGS); } nfetch=0 ; return_code = NOTFOUND; /* cursor open success */ while (sqlca.sqlcode == 0) { /* cursor서부터 data 하나씩 fetch */ EXEC SQL fetch CUR_1; /* fetch error */ if (sqlca.sqlcode ! = 0) { if (sqlca.sqlcode == NOTFOUND) break ; break ; } ACCT_V[nfetch].ACCOUNT_ID = account_id; strcpy(ACCT_V[nfetch].PHONE, phone ); strcpy(ACCT_V[nfetch].ADDRESS, address ); /* select한 데이터 개수 증가 */ nfetch++; return_code = nfetch /* NFETCH 개수만큼 select 했다면 while문 벗어남 */ if (nfetch > NFETCH) { nfetch = NFETCH; return_code = nfetch; break ; } } /* cursor close */ EXEC SQL close CUR_1; /* select의 결과와 그 데이터를 클라이언트에게 리턴 */ tpreturn ( TPSUCCESS, return_code, (char *)ACCT_V, sizeof(struct stru_acct)*nfetch, TPNOFLAGS); }
애플리케이션을 개발할 때 응용하여 사용할 수 있는 예제를 통해 실제 프로그래밍의 기법을 설명한다. 데이터베이스 연동은 동일 기종 데이터베이스와 이기종 데이터베이스로 나뉜다.
다음은 동기형 모드에서 동일 기종 데이터베이스에 접속하는 경우 프로그램 흐름에 대한 그림이다.
공통 프로그램
프로그램 파일 | 설명 |
---|---|
demo.s | SDLFILE이다. |
sample.m | Tmax 환경파일이다. |
tmax.env | 환경파일이다. |
mktable.sql | 데이터베이스에 테이블을 생성하는 SQL 스크립트이다. |
클라이언트 프로그램
프로그램 파일 | 설명 |
---|---|
client.c | 클라이언트 프로그램이다. |
서버 프로그램
프로그램 파일 | 설명 |
---|---|
update.pc, insert.pc | 서버 프로그램이다. |
Makefile | Tmax에서 제공되는 Makefile을 수정해야 한다. |
클라언트 프로그램
구분 | 설명 |
---|---|
Tmax 연결 | NULL 파라미터로 연결 |
버퍼 유형 | STRUCT |
하위 유형 | input 구조체 파일을 sdlc로 컴파일하여 SDL 파일 생성 필요 |
트랜잭션 여부 | 클라이언트에서 트랜잭션 지정 |
서버 프로그램
구분 | 설명 |
---|---|
서비스 수 | UPDATE 서비스에서 INSERT 서비스 요청 |
데이터베이스 연결 | Oracle 데이터베이스 사용 Tmax 환경파일의 SVRGROUP 절에 데이터베이스 정보 지정 |
구분 | 설명 |
---|---|
시스템 | SunOS 5.7 32bit |
데이터베이스 | Oracle 8.0.5 |
다음은 구조체 버퍼의 예제이다.
<demo.s>
struct input { int account_id; int branch_id; char phone[15]; char address[61]; };
다음은 Tmax 환경파일의 예제이다.
<sample.m>
*DOMAIN res SHMKEY=88000, MINCLH=1, MAXCLH=5, TPORTNO=8880, BLOCKTIME=60 *NODE tmax TMAXDIR = "/user/ tmax ", APPDIR = "/user/ tmax /appbin", PATHDIR = "/user/ tmax /path", TLOGDIR = "/user/ tmax /log/tlog", ULOGDIR="/user/ tmax /log/ulog", SLOGDIR="/user/ tmax /log/slog" *SVRGROUP svg1 NODENAME = tmax, DBNAME = ORACLE, OPENINFO = "ORACLE_XA+Acc=P/bmt/bmt+SesTm=60", TMSNAME = svg1_tms *SERVER update SVGNAME=svg1 insert SVGNAME=svg1 *SERVICE UPDATE SVRNAME=update INSERT SVRNAME=insert
다음은 환경파일의 예제이다.
<tmax.env>
[tmax] TMAX_HOST_ADDR=192.168.1.39 TMAX_HOST_PORT=8880 SDLFILE=/user/tmax/sample/sdl/tmax.sdl TMAX_CONNECT_TIMEOUT=5
다음은 데이터베이스 테이블을 생성하는 SQL 스크립트의 예제이다.
<mktable.sql>
$ORACLE_HOME/bin/sqlplus bmt/bmt <<! drop table ACCOUNT; create table ACCOUNT ( ACCOUNT_ID integer, BRANCH_ID integer not null, SSN char(13) not null, BALANCE number, ACCT_TYPE char(1), LAST_NAME char(21), FIRST_NAME char(21), MID_INIT char(1), PHONE char(15), ADDRESS char(61), CONSTRAINT ACCOUNT_PK PRIMARY KEY(ACCOUNT_ID) ); quit !
다음은 클라이언트 프로그램의 예제이다.
<client.c>
#include <stdio.h> #include <usrinc/atmi.h> #include "../sdl/demo.s" #define TEMP_PHONE "6283-2114" #define TEMP_ADDRESS "Korea" int main(int argc, char *argv[]) { struct input *sndbuf; char *rcvbuf; int acnt_id, n, timeout; long len; if (argc != 2) { fprintf(stderr, "Usage:%s account_id \n", argv[0]); exit(1); } acnt_id = atoi(argv[1]); timeout = 5; n = tmaxreadenv("tmax.env", "tmax"); if (n < 0) { fprintf(stderr, "tmaxreadenv fail! tperrno = %d\n", tperrno); exit(1); } n = tpstart((TPSTART_T *)NULL); if (n < 0) { fprintf(stderr, "tpstart fail! tperrno = %s\n", tperrno); exit(1); } sndbuf = (struct input *)tpalloc("STRUCT", "input", ` sizeof(struct input)); if (sndbuf == NULL) { fprintf(stderr, "tpalloc fail: sndbuf tperrno = %d\n", tperrno); tpend(); exit(1); } rcvbuf = (char *)tpalloc("STRING", NULL, 0); if (rcvbuf == NULL) { fprintf(stderr, "tpalloc fail: rcvbuf tperrno = %d\n", tperrno); tpend(); exit(1); } sndbuf->account_id = acnt_id; sndbuf->branch_id = acnt_id; strcpy(sndbuf ->phone, TEMP_PHONE); strcpy(sndbuf ->address, TEMP_ADDRESS); tx_set_transaction_timeout(timeout); n = tx_begin(); if (n < 0) fprintf(stderr, "tx begin fail! tperrno = %d\n", tperrno); n = tpcall("UPDATE", (char *)sndbuf, sizeof(struct input), (char **)&rcvbuf, (long *)&len, TPNOFLAGS); if (n < 0) { fprintf(stderr, "tpcall fail! tperrno = %d\n", tperrno); tpend(); exit(1); } n = tx_commit(); if (n < 0) { fprintf(stderr, "tx commit fail! tx error = %d \n", n); tx_rollback(); tpend(); exit(1); } printf("rtn msg = %s\n", rcvbuf); tpfree((char *)sndbuf); tpfree((char *)rcvbuf); tpend(); }
다음은 데이터베이스에 UPDATE하는 서버 프로그램의 예제이다.
<update.pc>
#include <stdio.h> #include <ctype.h> #include <usrinc/atmi.h> #include <usrinc/sdl.h> #include "../sdl/demo.s" #define OKMSG "YOU COMPLETE THE TRANSACTION" EXEC SQL include sqlca.h; EXEC SQL BEGIN DECLARE SECTION; int account_id; int branch_id; char ssn[15]; char phone[15]; char address[61]; EXEC SQL END DECLARE SECTION; UPDATE(TPSVCINFO *msg) { struct input *rcvbuf; int ret; long acnt_id, rcvlen; char *send; rcvbuf = (struct input *)(msg->data); send = (char *)tpalloc("STRING", NULL, 0); if (send == NULL) { fprintf(stderr, "tpalloc fail errno = %s\n", strerror(tperrno)); tpreturn(TPFAIL, 0, (char *)NULL, 0, 0); } account_id = rcvbuf->account_id; branch_id = rcvbuf->branch_id; }
다음은 데이터베이스에 INSERT하는 서버 프로그램의 예제이다.
< insert.pc>
#include <stdio.h> #include <ctype.h> #include <usrinc/atmi.h> #include <usrinc/sdl.h> #include "../sdl/demo.s" #define OKMSG "YOU COMPLETE THE TRANSACTION" EXEC SQL include sqlca.h; EXEC SQL BEGIN DECLARE SECTION; int account_id; int branch_id; char ssn[15]; char phone[15]; char address[61]; EXEC SQL END DECLARE SECTION; INSERT(msg) TPSVCINFO *msg; { struct input *rcvbuf; int ret; long acnt_id; char *send; rcvbuf = (struct input *)(msg->data); send = (char *)tpalloc("STRING", NULL, 0); if (send == NULL) { fprintf(stderr, "tpalloc fail errno = %s\n", tpstrerror(tperrno)); tpreturn(TPFAIL, 0, (char *)NULL, 0, TPNOFLAGS); } account_id = rcvbuf->account_id; branch_id = rcvbuf->branch_id; strcpy(phone, rcvbuf->phone); strcpy(address, rcvbuf->address); strcpy(ssn, "1234567"); /* Declare && Open Cursor for Fetch */ EXEC SQL INSERT INTO ACCOUNT ( ACCOUNT_ID, BRANCH_ID, SSN, PHONE, ADDRESS ) VALUES (:account_id, :branch_id, :ssn, :phone, :address); if (sqlca.sqlcode != 0 && sqlca.sqlcode != 1403 ) { printf("insert failed sqlcode = %d\n", sqlca.sqlcode); tpreturn(TPFAIL, -1, (char *)NULL, 0, TPNOFLAGS); } strcpy(send, OKMSG); tpreturn(TPSUCCESS, 1, (char *)send, strlen(send), TPNOFLAGS); }
다음은 동기형 모드에서 이기종 데이터베이스에 접속하는 경우 프로그램 흐름에 대한 그림이다.
공통 프로그램
프로그램 파일 | 설명 |
---|---|
demo.s | SDLFILE이다. |
sample.m | Tmax 환경파일이다. |
tmax.env | 환경파일이다. |
mktable.sql | 데이터베이스에 테이블을 생성하는 SQL 스크립트이다. |
클라이언트 프로그램
구성 | 설명 |
---|---|
client.c | 클라이언트 프로그램이다. |
서버 프로그램
구성 | 설명 |
---|---|
update.pc, insert.pc | 서버 프로그램이다. |
Makefile | Tmax에서 제공되는 Makefile을 수정해야 한다. |
클라이언트와 서버프로그램 등 모두 “5.4.1. 동기형 모드(동일 기종)”의 경우와 같다. 멀티 노드 환경 설정에 대한 자세한 내용은 "Tmax Administration Guide"를 참고한다.
클라이언트 프로그램
구분 | 설명 |
---|---|
Tmax 연결 | NULL 파라미터로 연결 |
버퍼 유형 | STRUCT |
하위 유형 | input 구조체 파일을 sdlc로 컴파일하여 SDL 파일 생성 필요 |
트랜잭션 여부 | 클라이언트에서 명시적으로 트랜잭션 범위 지정 |
서버 프로그램
구분 | 설명 |
---|---|
서비스 수 | UPDATE 서비스에서 INSERT 서비스를 요청 |
데이터베이스 연결 | Oracle 데이터베이스를 사용하고 시스템 구성 파일의 SVRGROUP 절에 데이터베이스 정보 지정 |
구분 | 설명 |
---|---|
시스템 | SunOS 5.7 32bit, SunOS 5.8 32bit |
데이터베이스 | Oracle 8.0.5 |
다음은 Tmax 환경파일의 예제이다.
<sample.m>
*DOMAIN res SHMKEY=88000, MINCLH=1, MAXCLH=5, TPORTNO=8880, BLOCKTIME=60 *NODE tmax1 TMAXDIR="/user/ tmax ", APPDIR="/user/ tmax /appbin", PATHDIR = "/user/ tmax /path", TLOGDIR = "/user/ tmax /log/tlog", ULOGDIR="/user/ tmax /log/ulog", SLOGDIR="/user/ tmax /log/slog" tmax2 TMAXDIR="/user/ tmax ", APPDIR="/user/ tmax /appbin", PATHDIR = "/user/ tmax /path", TLOGDIR = "/user/ tmax /log/tlog", ULOGDIR="/user/ tmax /log/ulog", SLOGDIR="/user/ tmax /log/slog" *SVRGROUP svg1 NODENAME = tmax1, DBNAME = ORACLE, OPENINFO = "ORACLE_XA+Acc=P/bmt/bmt+SesTm=60", TMSNAME = svg1_tms svg2 NODENAME = tmax2, DBNAME = ORACLE, OPENINFO = "ORACLE_XA+Acc=P/bmt/bmt+SesTm=60", TMSNAME = svg2_tms *SERVER update SVGNAME=svg1 insert SVGNAME=svg2 *SERVICE UPDATE SVRNAME=update INSERT SVRNAME=insert
다음은 환경파일의 예제이다.
[tmax1] TMAX_HOST_ADDR=192.168.1.39 TMAX_HOST_PORT=8880 SDLFILE=/user/tmax/sample/sdl/tmax.sdl TMAX_CONNECT_TIMEOUT=5
다음은 비동기형 모드에서 동일 기종데이터베이스에 접속하는 경우 프로그램 흐름에 대한 그림이다.
공통 프로그램
프로그램 파일 | 설명 |
---|---|
demo.s | SDLFILE이다. |
sample.m | Tmax 환경파일이다. |
tmax.env | 환경파일이다. |
mktable.sql | 데이터베이스에 테이블을 생성하는 SQL 스크립트이다. |
클라이언트 프로그램
프로그램 파일 | 설명 |
---|---|
client.c | 클라이언트 프로그램이다. |
서버 프로그램
프로그램 파일 | 설명 |
---|---|
update.pc | 서버 프로그램이다. |
Makefile | Tmax에서 제공되는 Makefile로 수정해야 한다. |
클라이언트 프로그램
기능 | 설명 |
---|---|
Tmax 연결 | NULL 파라미터로 연결 |
버퍼 유형 | STRUCT |
하위 유형 | input 구조체 파일을 sdlc로 컴파일하여 SDL 파일 생성 필요 |
트랜잭션 여부 | 클라이언트에서 트랜잭션 지정 |
서버 프로그램
기능 | 설명 |
---|---|
서비스 수 | UPDATE 서비스 요청 |
데이터베이스 연결 | Orale 데이터베이스 사용하고 시스템 구성 파일의 SVRGROUP 절에 데이터베이스 정보 지정 |
구분 | 설명 |
---|---|
시스템 | SunOS 5.7 32bit |
데이터베이스 | Oracle 8.0.5 |
다음은 구조체 버퍼의 예제이다.
<demo.s>
struct input { int account_id; int branch_id; char phone[15]; char address[61]; };
다음은 Tmax 환경파일의 예제이다.
<sample.m>
*DOMAIN res SHMKEY=88000, MINCLH=1, MAXCLH=5, TPORTNO=8880, BLOCKTIME=60 *NODE tmax TMAXDIR="/user/ tmax ", APPDIR="/user/ tmax /appbin", PATHDIR = "/user/ tmax /path", TLOGDIR = "/user/ tmax /log/tlog", ULOGDIR="/user/ tmax /log/ulog", SLOGDIR="/user/ tmax /log/slog" *SVRGROUP svg1 NODENAME = tmax, DBNAME = ORACLE, OPENINFO = "ORACLE_XA+Acc=P/bmt/bmt+SesTm=60", TMSNAME = svg1_tms *SERVER update SVGNAME=svg1 *SERVICE UPDATE SVRNAME=update
다음은 환경파일의 예제이다.
<tmax.env>
[tmax] TMAX_HOST_ADDR=192.168.1.39 TMAX_HOST_PORT=8880 SDLFILE=/user/tmax/sample/sdl/tmax.sdl TMAX_CONNECT_TIMEOUT=5
다음은 데이터베이스에 테이블을 생성하는 SQL 스크립트의 예제이다.
<mktable.sql>
$ORACLE_HOME/bin/sqlplus bmt/bmt <<! drop table ACCOUNT; create table ACCOUNT ( ACCOUNT_ID integer, BRANCH_ID integer not null, SSN char(13) not null, BALANCE number, ACCT_TYPE char(1), LAST_NAME char(21), FIRST_NAME char(21), MID_INIT char(1), PHONE char(15), ADDRESS char(61), CONSTRAINT ACCOUNT_PK PRIMARY KEY(ACCOUNT_ID) ); quit !
다음은 클라이언트 프로그램의 예제이다.
<client.c>
#include <stdio.h> #include <usrinc/atmi.h> #include "../sdl/demo.s" #define TEMP_PHONE "6283-2114" #define TEMP_ADDRESS "Korea" int main(int argc, char *argv[]) { struct input *sndbuf; char *rcvbuf; int acnt_id, n, cd, timeout; long len; if (argc != 2) { fprintf(stderr, "Usage:%s account_id \n", argv[0]); exit(1); } acnt_id = atoi(argv[1]); timeout = 5; n = tmaxreadenv("tmax.env", "tmax"); if (n < 0) { fprintf(stderr, "tmaxreadenv fail! tperrno = %d\n", tperrno); exit(1); } n = tpstart((TPSTART_T *)NULL); if (n < 0) { fprintf(stderr, "tpstart fail! tperrno = %s\n", tperrno); exit(1); } sndbuf = (struct input *)tpalloc("STRUCT", "input", sizeof(struct input)); if (sndbuf == NULL) { fprintf(stderr, "tpalloc fail: sndbuf tperrno = %d\n", tperrno); tpend(); exit(1); } rcvbuf = (char *)tpalloc("STRING", NULL, 0); if (rcvbuf == NULL) { fprintf(stderr, "tpalloc fail: rcvbuf tperrno = %d\n", tperrno); tpend(); exit(1); } sndbuf->account_id = acnt_id; sndbuf->branch_id = acnt_id; strcpy(sndbuf->phone, TEMP_PHONE); strcpy(sndbuf->address, TEMP_ADDRESS); tx_set_transaction_timeout(timeout); n = tx_begin(); if (n < 0) fprintf(stderr, "tx begin fail! tperrno = %d\n", tperrno); cd = tpacall("UPDATE", (char *)sndbuf, sizeof(struct input), TPNOFLAGS); if (cd < 0) { fprintf(stderr, "tpacall fail! tperrno = %d\n", tperrno); tpend(); exit(1); } n = tpgetrply(&cd, (char **)&rcvbuf, (long *)&len, TPNOFLAGS); if (n < 0) { fprintf(stderr, "tpgetrply fail! tperrno = %d\n", tperrno); tpend(); exit(1); } n = tx_commit(); if (n < 0) { fprintf(stderr, "tx commit fail! tx error = %d \n", n); tx_rollback(); tpend(); exit(1); } printf("rtn msg = %s\n", rcvbuf); tpfree((char *)sndbuf); tpfree((char *)rcvbuf); tpend(); }
다음은 서버 프로그램의 예제이다.
<update.pc>
#include <stdio.h> #include <ctype.h> #include <usrinc/atmi.h> #include "../sdl/demo.s" #define OKMSG "YOU COMPLETE THE TRANSACTION" EXEC SQL include sqlca.h; EXEC SQL BEGIN DECLARE SECTION; int account_id; int branch_id; char ssn[15]; char phone[15]; char address[61]; EXEC SQL END DECLARE SECTION; UPDATE(TPSVCINFO *msg) { struct input *rcvbuf; int ret, cd; long acnt_id, rcvlen; char *send; rcvbuf = (struct input *)(msg->data); send = (char *)tpalloc("STRING", NULL, 0); if (send == NULL) { fprintf(stderr, "tpalloc fail errno = %s\n", strerror(tperrno)); tpreturn(TPFAIL, 0, (char *)NULL, 0, TPNOFLAGS); } account_id = rcvbuf->account_id; branch_id = rcvbuf->branch_id; strcpy(phone, rcvbuf->phone); strcpy(address, rcvbuf->address); strcpy(ssn, "1234567"); EXEC SQL UPDATE ACCOUNT SET BRANCH_ID = :branch_id, PHONE = :phone, ADDRESS = :address, SSN = :ssn WHERE ACCOUNT_ID = :account_id; if (sqlca.sqlcode != 0 && sqlca.sqlcode != 1403 ) { fprintf(stderr, "update failed sqlcode = %d\n", sqlca.sqlcode); tpreturn(TPFAIL, -1, (char *)NULL, 0, TPNOFLAGS); } strcpy(send, OKMSG); tpreturn(TPSUCCESS, 1, (char *)send, strlen(send), TPNOFLAGS); }
다음은 대화형 모드에서 동일 기종 데이터베이스에 접속하는 경우 프로그램 흐름에 대한 그림이다.
공통 프로그램
프로그램 파일 | 설명 |
---|---|
demo.s | SDLFILE이다. |
sample.m | Tmax 환경파일이다. |
tmax.env | 환경파일이다. |
mktable.sql | 데이터베이스에 테이블을 생성하는 SQL 스크립트이다. |
클라이언트 프로그램
프로그램 파일 | 설명 |
---|---|
client.c | 클라이언트 프로그램이다. |
서버 프로그램
프로그램 파일 | 설명 |
---|---|
update.pc | 서버 프로그램이다. |
Makefile | Tmax에서 제공되는 Makefile을 수정해야 한다. |
클라이언트 프로그램
기능 | 설명 |
---|---|
Tmax 연결 | NULL 파라미터로 연결 |
버퍼 유형 | STRUCT |
하위 유형 | input 구조체 파일을 sdlc로 컴파일하여 SDL 파일 생성 필요 (애플리케이션을 실행시키기 위해 필요) |
트랜잭션 여부 | 클라이언트에서 트랜잭션 지정 |
서버 프로그램
기능 | 설명 |
---|---|
서비스 수 | UPDATE 서비스를 요청 |
데이터베이스 연결 | Oracle 데이터베이스 지정하고 Tmax 환경파일의 SVRGROUP 절에 데이터베이스 정보 지정 |
구분 | 설명 |
---|---|
시스템 | SunOS 5.7 32bit |
데이터베이스 | Oracle 8.0.5 |
다음은 구조체 버퍼의 예제이다.
<demo.s>
struct input { int account_id; int branch_id; char phone[15]; char address[61]; };
다음은 Tmax 환경파일의 예제이다.
*DOMAIN res SHMKEY=88000, MINCLH=1, MAXCLH=5, TPORTNO=8880, BLOCKTIME=60 *NODE tmax TMAXDIR="/user/ tmax ", APPDIR="/user/ tmax /appbin", PATHDIR = "/user/ tmax /path", TLOGDIR = "/user/ tmax /log/tlog", ULOGDIR="/user/ tmax /log/ulog", SLOGDIR="/user/ tmax /log/slog" *SVRGROUP svg1 NODENAME = tmax, DBNAME = ORACLE, OPENINFO = "ORACLE_XA+Acc=P/bmt/bmt+SesTm=60", TMSNAME = svg1_tms *SERVER update SVGNAME=svg1, CONV=YES *SERVICE UPDATE SVRNAME= update
다음은 환경파일의 예제이다.
<tmax.env>
[tmax] TMAX_HOST_ADDR=192.168.1.39 TMAX_HOST_PORT=8880 SDLFILE=/user/tmax/sample/sdl/tmax.sdl TMAX_CONNECT_TIMEOUT=5
다음은 데이터베이스에 테이블을 생성하는 SQL 스크립트의 예제이다.
<mktable.sql>
$ORACLE_HOME/bin/sqlplus bmt/bmt <<! drop table ACCOUNT; create table ACCOUNT ( ACCOUNT_ID integer, BRANCH_ID integer not null, SSN char(13) not null, BALANCE number, ACCT_TYPE char(1), LAST_NAME char(21), FIRST_NAME char(21), MID_INIT char(1), PHONE char(15), ADDRESS char(61), CONSTRAINT ACCOUNT_PK PRIMARY KEY(ACCOUNT_ID) ); quit !
다음은 클라이언트 프로그램의 예제이다.
<client.c>
#include <stdio.h> #include <usrinc/atmi.h> #include "../sdl/demo.s" #define TEMP_PHONE "6283-2115" #define TEMP_ADDRESS "Korea" void main(int argc, char *argv[]) { struct input *sndbuf; char *rcvbuf; int acntid, timeout; long revent, rcvlen; int cd, n; if (argc != 2) { fprintf(stderr, "Usage:%s acntid\n", argv[0]); exit(1); } acntid = atoi(argv[1]); timeout = 5; n = tmaxreadenv("tmax.env", "tmax"); if (n < 0) { fprintf(stderr, "tmaxreadenv fail tperrno = %d\n", tperrno); exit(1); } n = tpstart((TPSTART_T *)NULL); if (n < 0) { fprintf(stderr, "tpstart fail tperrno = %s\n", tperrno); exit(1); } printf("tpstart ok!\n"); sndbuf = (struct input *)tpalloc("STRUCT", "input", sizeof(struct input)); if (sndbuf == NULL) { fprintf(stderr, "tpalloc fail: sndbuf tperrno = %d\n", tperrno); tpend(); exit(1); } rcvbuf = (char *)tpalloc("CARRAY", NULL, 0); if (rcvbuf == NULL) { fprintf(stderr, "tpalloc fail: rcvbuf tperrno = %d\n", tperrno); tpend(); exit(1); } sndbuf->account_id = acntid; sndbuf->branch_id = acntid; strcpy(sndbuf->phone, TEMP_PHONE); strcpy(sndbuf->address, TEMP_ADDRESS); tx_set_transaction_timeout(timeout); n = tx_begin(); if (n < 0) fprintf(stderr, "tx begin fail tx error = %d\n", n); printf("tx begin ok!\n"); cd = tpconnect("UPDATE", (char *)sndbuf, 0, TPSENDONLY); if (cd < 0) { fprintf(stderr, "tpconnect fail tperrno = %d\n", tperrno); tpend(); exit(1); } while (1) { n = tpsend(cd, (char *)sndbuf, sizeof(struct input), TPRECVONLY, &revent); if (n < 0) { fprintf(stderr, "tpsend fail revent = 0x%08x\n", revent); tx_rollback(); tpend(); exit(1); } printf("tpsend ok\n"); n = tprecv(cd, (char **)&rcvbuf, (long *)&rcvlen, TPNOTIME, &revent); if (n < 0 && revent != TPEV_SENDONLY) { fprintf(stderr, "tprecv fail revent = 0x%08x\n", revent); tx_rollback(); tpend(); exit(1); } printf("tprecv ok\n"); sndbuf->account_id++; if (revent != TPEV_SENDONLY) break; } n = tprecv(cd, (char **)&rcvbuf, (long *)&rcvlen, TPNOTIME, &revent); if (n < 0 && revent != TPEV_SVCSUCC) { fprintf(stderr, "tprecv fail revent = 0x%08x\n", revent); tx_rollback(); tpend(); exit(1); } printf("rcvbuf = [%s]\n", rcvbuf); n = tx_commit(); if (n < 0) { fprintf(stderr, "tx commit fail tx error = %d\n", n); tx_rollback(); tpend(); exit(1); } printf("tx commit ok!\n"); printf("rtn msg = %s\n", rcvbuf); tpfree((char *)sndbuf); tpfree((char *)rcvbuf); tpend(); }
다음은 서버 프로그램의 예제이다.
<update.pc>
#include <stdio.h> #include <ctype.h> #include <usrinc/atmi.h> #include "../sdl/demo.s" void _db_work(); #define OKMSG "YOU COMPLETE THE TRANSACTION" EXEC SQL include sqlca.h; EXEC SQL BEGIN DECLARE SECTION; int account_id; int branch_id; char ssn[15]; char phone[15]; char address[61]; EXEC SQL END DECLARE SECTION; struct input *rcvbuf; UPDATE(TPSVCINFO *msg) { int ret, count; long acnt_id; long revent, rcvlen, flag; char *send; rcvbuf = (struct input *)tpalloc("STRUCT", "input", 0); send = (char *)tpalloc("CARRAY", NULL, 0); count = 1; flag = 0; while (1) { ret = tprecv(msg->cd, (char **)&rcvbuf, &rcvlen, TPNOTIME, &revent); if (ret < 0 && revent != TPEV_SENDONLY) { fprintf(stderr, "tprecv fail revent = 0x%08x\n", revent); tpreturn(TPFAIL, -1, (char *)rcvbuf, 0, TPNOFLAGS); } printf("tprecv ok!\n"); if (count == 10) { flag &= ~TPRECVONLY; flag |= TPNOTIME; } else flag |= TPRECVONLY; ret = tpsend(msg->cd, (char *)send, strlen(send), flag, &revent); if (ret < 0) { fprintf(stderr, "tpsend fail revent = 0x%08x\n", revent); tpreturn(TPFAIL, -1, (char *)NULL, 0, TPNOFLAGS); } printf("tpsend ok!\n"); _db_work(); /* break after 10 iterations */ if (count == 10) break; count++; } strcpy(send, OKMSG); printf("tpreturn ok!\n"); tpreturn(TPSUCCESS, 1, (char *)send, strlen(send), TPNOFLAGS); } void _db_work() { account_id = rcvbuf->account_id; branch_id = rcvbuf->branch_id; strcpy(phone, rcvbuf->phone); strcpy(address, rcvbuf->address); strcpy(ssn, "1234567"); EXEC SQL UPDATE ACCOUNT SET BRANCH_ID = :branch_id, PHONE = :phone, ADDRESS = :address, SSN = :ssn WHERE ACCOUNT_ID = :account_id; if (sqlca.sqlcode != 0 && sqlca.sqlcode != 1403 ) { fprintf(stderr, "update failed sqlcode = %d\n", sqlca.sqlcode); tpreturn(TPFAIL, -1, (char *)NULL, 0, 0); } }
Tmax에서는 TIP(Tmax Information Provider)를 사용하여 시스템 환경 정보, 통계 정보 확인, 시스템 운용 관리 등 다양한 기능을 수행할 수 있다. TIP은 TIPSVC를 처리하기 위하여 Tmax에서 제공하는 기능 프로세스로, TIP을 사용하여 다음의 기능을 수행할 수 있다.
시스템 환경 정보 확인: 시스템의 정적인 환경 정보를 확인한다.
시스템 통계 정보 확인: 시스템 운영 중에 각각 프로세스의 상태 등을 확인한다.
시스템 운용 관리: 프로세스를 추가로 기동하거나 종료한다.
TIPSVC를 처리하기 위한 별도의 기능 프로세스인 TIP 서버는 SYS_SVR 서버 타입을 가지며, TIP 서버 그룹에 속한다. 클라이언트 혹은 서버의 요청을 받은 TIP 서버는 그 요청을 CLH/TMM에게 전달하여 처리 결과를 다시 요청자에게 돌려준다. TIP 서버는 필드 키를 바탕으로 서비스를 처리한다. 요청하는 클라이언트나 서버는 필드 버퍼에 요구하려는 데이터를 실어 요청을 하며, 그 결과를 필드 버퍼로 받는다.
CHLOG section (로그 레벨 변경)
CHLOG는 TMM, CLH, TMS, SVR 의 log level을 변경할 수 있는 섹션이다. tmadmin 에서 chlog를 실행하는 것과 동일한 동작을 수행한다.
TIP 서비스를 호출할 경우, 필드 버퍼에 아래를 설정하여 TIPSVC를 호출한다.
항목 | 설명 |
---|---|
TIP_OPERATION (string) | GET으로 설정한다. |
TIP_SEGMENT (string) | ADMINISTRATION으로 설정한다. |
TIP_SECTION (string) | CHLOG로 설정한다. |
TIP_MODULE (int) | 동적으로 로그를 변경하고 싶은 모듈을 설정하는 항목으로 다음 중 하나를 선택한다. TIP_TMM | TIP_CLH | TIP_TMS | TIP_SVR |
TIP_FLAGS (int) | flags를 설정하는 항목으로 다음 중 하나를 선택한다. TIP_VFLAG | TIP_GFLGA | TIP_NFLAG |
TIP_SVRNAME (string) | 해당 서버명을 설정하는 항목으로 TIP_FLAGS를 TIP_VFLAG로 설정한 경우에만 설정한다. |
TIP_SVGNAME (string) | 해당 서버 그룹명을 설정하는 항목으로 TIP_FLAGS를 TIP_GFLAG로 설정한 경우에만 설정한다. |
TIP_NODENAME (string) | 해당 노드명으로 TIP_FLAGS를 TIP_NFLAG로 설정한 경우에만 설정한다. |
TIP_LOGLVL (string) | 변경하고자 하는 로그 레벨을 설정하는 항목으로 다음 중에 하나를 선택하고 반드시 소문자로 설정한다. 결과로 받아오는 값은 TIP_ERROR에 설정된다. compact | basic | detail | debug1 | debug2 | debug3 | debug4 |
TIP_ERROR (int) | 에러값이 설정되는 항목으로 설정되는 에러값은 다음과 같다.
|
CHTRC section
TMS와 SPR의 TMAX_TRACE를 수정하여 trace log 옵션을 변경할 수 있는 섹션이다. tmadmin의 chtrc와 동일한 동작을 수행한다.
TIP 서비스를 호출할 경우, 필드 버퍼에 아래를 설정하여 TIPSVC를 호출한다.
항목 | 설명 |
---|---|
TIP_OPERATION (string) | GET으로 설정해야 한다. |
TIP_SEGMENT (string) | ADMINISTRATION으로 설정해야 한다. |
TIP_SECTION (string) | CHTRC로 설정해야 한다. |
TIP_FLAGS (int) | flags를 설정하는 항목으로 다음 중에 하나를 설정한다. TIP_PFLAG| TIP_VFLAG | TIP_GFLAG | TIP_NFLAG |
TIP_SPRI (int) | spri를 설정하는 항목으로 TIP_FLAGS를 TIP_PFLAG로 설정한 경우에만 설정한다. |
TIP_SVGNAME (string) | 해당 서버 그룹명을 설정하는 항목으로 TIP_FLAGS를 TIP_GFLAG로 설정한 경우에만 설정한다. |
TIP_NODENAME (string) | 해당 노드명을 설정하는 항목으로 TIP_FLAGS를 TIP_NFLAG로 설정한 경우에만 설정한다. |
TIP_SPEC (string) | 변경하고자 하는 filter spec, receiver spec, trigger spec을 설정하는 항목이다. 결과로 받아오는 값은 TIP_ERROR에 설정된다. |
TIP_ERROR (int) | 에러값이 설정된다. 설정되는 에러값은 다음과 같다.
|
다음은 TIPSVC에 요청하기 위하여 포함해야 할 데이터이다.
조직(TIP_OPERATION)
설정값 | 설명 |
---|---|
GET | 시스템의 정적인 환경 정보, 통계 정보의 확인, BOOT/DOWN 시스템 운용 관리할 경우에는 GET으로 설정한다. |
SET | 시스템 설정 상태를 변경하려고 하는 경우에 SET으로 설정한다. 현재는 GET만 사용된다. |
세그먼트(TIP_SEGMENT)
어떤 기능을 수행할지 결정하기 위하여 사용하는 필드로 다음은 TIP_SEGMENT 필드에 설정할 수 있는 값이다.
설정값 | 설명 |
---|---|
CONFIGURATION | 시스템의 정적인 설정 정보를 확인한다. |
STATISTICS | 시스템의 운영 중에 통계 정보를 확인한다. |
ADMINISTRATION | 시스템 운용 관리(BOOT/DOWN)를 확인한다. |
절(TIP_SECTION)
TIP_SECTION을 설정했을 경우 어떤 항목에 대하여 처리를 할 것인지 세부 항목을 결정한다.
설정값 | 설명 |
---|---|
CONFIGURATION | DOMAIN, NODE, SVRGROUP, SERVER, SERVICE, ROUTING, RQ, GATEWAY |
STATISTICS | NODE, SPR, SERVICE, RQ |
ADMINISTRATION | BOOT, DOWN, CHLOG, CHTRC |
명령어(TIP_CMD)
필드는 TIP_SECTION이 ADMINISTRATION일 경우에만 사용된다.
설정값 | 설명 |
---|---|
TIP_BOOT | Tmax 시스템을 기동한다. |
TIP_DOWN | Tmax 시스템을 종료한다. |
TIP의 사용 방법과 에러 확인하는 방법에 대해 설명한다.
환경 설정
TIP 서버는 Tmax에서 제공하는 기능 프로세스이기 때문에 사용자가 서비스를 작성할 필요가 없다. 단, 환경파일에 TIP 서버를 등록해야 한다. 다음은 환경 설정의 예제이다.
*DOMAIN res ..., TIPSVC = TIPSVC *NODE tmaxs1 ... *SVRGROUP tsvg ..., SVGTYPE = TIP *SERVER TIP SVGNAME = tsvg, SVRTYPE = SYS_SVR
DOMAIN 절에는 TIPSVC를 등록한다. 등록하지 않을 경우에는 기본값으로 TIPSVC가 등록된다.
SVRGROUP 절에는 TIP 서버 그룹(SVGTYPE=TIP)을 등록한다.
SERVER 절에는 TIP 서버(SVRTYPE=SYS_SVR)를 등록한다.
Tmax v5.0 SP2 Fix#1부터 TIP 서버의 MIN, MAX 설정을 1 이상으로 설정할 수 있다. 따라서 여러 개의 TIP 서버가 기동되어 TIPSVC 요청들을 동시에 처리할 수 있다.
시스템 접속
사용자는 Tmax 시스템 접속할 때에 TPSTART_T 구조체의 usrname 항목에 .tpadmin을 설정해야 한다. TIP_SEGMENT가 ADMINISTRATION일 경우에만 usrname을 설정하며, 다른 경우에는 설정하지 않아도 된다. 잘못된 usrname이 설정되었을 경우에는 TIP_ERROR 필드에 TIPEAUTH 에러가 설정된다.
strcpy(tpinfo->usrname, “.tpadmin”);
버퍼 할당
TIP 서버는 필드키를 바탕으로 서비스를 처리하므로 요청하는 클라이언트나 서버 프로그램은 필드키 버퍼를 할당해야 한다.
TIP 요청 항목 설정
항목 | 설명 |
---|---|
TIP_OPERATION | 시스템 환경정보 변경 및 확인할 경우 설정한다. |
TIP_SEGMENT | 시스템 정보확인 및 운영관리를 위해서 설정한다. |
TIP_SECTION | SEGMENT에서 설정항목에 대한 세부처리를 설정한다. |
TIP_CMD | TIP_SEGMENT가 ADMINISTRATION일 경우만 설정한다. |
TIP_NODENAME | 멀티 노드일 경우만 설정하며, 단일 노드일 경우 지정하지 않으면 기본값으로 로컬 노드가 설정된다. 잘못 설정하였을 경우 TPEINVAL 에러가 발생한다. |
TIPSVC 요청
TIP 요청 항목을 설정하였다면 설정한 필드 버퍼를 sndbuf로 하여, tpcall이나 tpacall을 이용하여 TIPSVC로 요청을 한다. 클라이언트, 서버에서 모두 요청할 수 있으며, 트랜잭션은 지원하지 않는다.
결과 수신
수신 필드키 버퍼에 서비스 결과가 저장된다.
정상 처리된 경우
수신 필드키 버퍼의 TIP_ERROR 항목에 0이 설정된다.
에러가 발생한 경우
에러 | 설명 |
---|---|
TIP_STATUS | TIP_ERROR에 설정된 에러 내용에 대하여 상세한 에러 내용을 확인할 수 있다. |
TIP_BADFIELD | 에러를 유발시킨 필드를 확인할 수 있다. |
TIP_ERROR | 수신 필드키 버퍼의 TIP_ERROR 항목에 0보다 큰 값이 설정된다. 이는 /usrinc/tip.h에서 확인할 수 있다. |
다음은 TIP_ERROR에 설정되는 에러값에 대한 설명이다.
설정값 | 설명 |
---|---|
TIPNOERROR | 에러가 발생하지 않는다. |
TIPEBADFLD | 유효하지 않은 필드키가 사용되었다. 일반적으로 fdlc 유틸리티를 사용하여 컴파일되지 않은 필드키가 사용되었을 경우 TIP_ERROR는 TIPEBADFLD로 설정된다. |
TIPEIMPL | 구현되지 않은 기능에 대하여 요청한 경우이다. |
TIPEAUTH | 현재의 권한으로는 허용되지 않는 서비스이다. |
TIPEOS | 운영 시스템 또는 시스템 에러로서 메모리 할당 실패, Tmax 시스템에 접속 실패, 또는 네트워크 상태가 불안정할 경우 등에 나타나는 에러이다. |
TIPENOENT | 존재하지 않는 항목을 접근하는 경우에 발생한다. |
TIPESVCFAIL | TIP 서비스 루틴이 에러가 발생하여 TPFAIL로 tpreturn()을 호출하였다. |
본 절은 TIP를 사용한 예제를 설명한다.
다음은 단일 노드를 사용한 예제이다.
<cfg.m>
*DOMAIN res SHMKEY=78850, MAXUSER=200, MINCLH=1, MAXCLH=5, TPORTNO=8850, BLOCKTIME=60, TXTIME=50, RACPORT=3355 *NODE tmaxh4 TMAXDIR="/data1/starbj81/tmax", APPDIR="/data1/starbj81/tmax/appbin", PATHDIR ="/data1/starbj81/tmax/path", TLOGDIR ="/data1/starbj81/tmax/log/tlog", ULOGDIR="/data1/starbj81/tmax/log/ulog", SLOGDIR="/data1/starbj81/tmax/log/slog" *SVRGROUP tsvg NODENAME = "tmaxh4", SVGTYPE=TIP svg1 NODENAME = "tmaxh4" *SERVER TIP SVGNAME=tsvg, SVRTYPE=SYS_SVR, MIN=1, MAX=1 svr SVGNAME=svg1, MIN=1 *SERVICE TOUPPER SVRNAME=svr
다음은 멀티 노드를 사용한 예제이다.
<cfg.m>
*DOMAIN tmax SHMKEY=98850, TPORTNO=8850, BLOCKTIME=60, RACPORT=3355, MAXUSER=10 *NODE Tmaxh4 TMAXDIR="/data1/starbj81/tmax", APPDIR="/data1/starbj81/tmax/appbin", PATHDIR = "/data1/starbj81/tmax/path", TLOGDIR = "/data1/starbj81/tmax/log/tlog", ULOGDIR="/data1/starbj81/tmax/log/ulog", SLOGDIR="/data1/starbj81/tmax/log/slog" tmaxh2 TMAXDIR="/data1/starbj81/tmax", APPDIR="/data1/starbj81/tmax/appbin", PATHDIR = "/data1/starbj81/tmax/path", TLOGDIR = "/data1/starbj81/tmax/log/tlog", ULOGDIR="/data1/starbj81/tmax/log/ulog", SLOGDIR="/data1/starbj81/tmax/log/slog" *SVRGROUP tsvg NODENAME = "tmaxh4", SVGTYPE=TIP svg1 NODENAME = "tmaxh4", COUSIN = "svg2" svg2 NODENAME = "tmaxh2" *SERVER TIP SVGNAME=tsvg, SVRTYPE=SYS_SVR, MIN=1, MAX=1 svr SVGNAME=svg1, MIN=1, MAX=5 *SERVICE TOUPPER SVRNAME=svr, ROUTING = "rout1" *ROUTING rout1 FIELD="STRING", RANGES = "'bbbbbbb'-'ccccccc' : svg1, * : svg2
다음은 필드키 테이블의 예제이다.
< tip.f >
# # common field # # name number type flags comments *base 16000001 TIP_OPERATION 0 string TIP_SEGMENT 1 string TIP_SECTION 2 string TIP_NODE 3 string TIP_OCCURS 4 int TIP_FLAGS 5 int TIP_CURSOR 6 string TIP_SESTM 7 int TIP_ERROR 8 int TIP_STATE 9 int TIP_MORE 10 int TIP_BADFIELD 11 string TIP_CMD 12 string TIP_CLID 13 int TIP_MSG 14 string # # DOMAIN section fields # # name number type flags comments *base 16000100 TIP_NAME 0 string TIP_SHMKEY 1 int TIP_MINCLH 2 int TIP_MAXCLH 3 int TIP_MAXUSER 4 int TIP_TPORTNO 5 int TIP_RACPORT 6 int TIP_MAXSACALL 7 int TIP_MAXCACALL 8 int TIP_MAXCONV_NODE 9 int TIP_MAXCONV_SERVER 10 int TIP_CMTRET 11 int TIP_BLOCKTIME 12 int TIP_TXTIME 13 int TIP_IDLETIME 14 int TIP_CLICHKINT 15 int TIP_NLIVEINQ 16 int TIP_SECURITY 17 string TIP_OWNER 18 string TIP_CPC 19 int #TIP_LOGINSVC 20 string #TIP_LOGOUTSVC 21 string TIP_NCLHCHKTIME 22 int TIP_DOMAINID 23 int TIP_IPCPERM 24 int TIP_MAXNODE 25 int TIP_MAXSVG 26 int TIP_MAXSVR 27 int TIP_MAXSVC 28 int TIP_MAXSPR 29 int TIP_MAXTMS 30 int TIP_MAXCPC 31 int TIP_MAXROUT 32 int TIP_MAXROUTSVG 33 int TIP_MAXRQ 34 int TIP_MAXGW 35 int TIP_MAXCOUSIN 36 int TIP_MAXCOUSINSVG 37 int TIP_MAXBACKUP 38 int TIP_MAXBACKUPSVG 39 int TIP_MAXTOTALSVG 40 int TIP_MAXPROD 41 int TIP_MAXFUNC 42 int TIP_TXPENDINGTIME 43 int TIP_NO 44 int TIP_TIPSVC 45 string TIP_NODECOUNT 46 int TIP_SVGCOUNT 47 int TIP_SVRCOUNT 48 int TIP_SVCCOUNT 49 int TIP_COUSIN_COUNT 50 int TIP_BACKUP_COUNT 51 int TIP_ROUT_COUNT 52 int TIP_STYPE 53 string TIP_VERSION 54 string TIP_EXPDATE 55 string TIP_DOMAINCOUNT 56 int TIP_RSVG_GCOUNT 57 int TIP_RSVG_COUNT 58 int TIP_CSVG_GCOUNT 59 int TIP_CSVG_COUNT 60 int TIP_BSVG_GCOUNT 61 int TIP_BSVG_COUNT 62 int TIP_PROD_COUNT 63 int TIP_FUNC_COUNT 64 int TIP_SHMSIZE 65 int TIP_CRYPT 66 string TIP_DOMAIN_TMMLOGLVL 67 string TIP_DOMAIN_CLHLOGLVL 68 string TIP_DOMAIN_TMSLOGLVL 69 string TIP_DOMAIN_LOGLVL 70 string TIP_DOMAIN_MAXTHREAD 71 int # # NODE section fields # # name number type flags comments *base 16000200 #TIP_NAME 0 string TIP_DOMAINNAME 1 string #TIP_SHMKEY 2 int #TIP_MINCLH 3 int #TIP_MAXCLH 4 int TIP_CLHQTIMEOUT 5 int #TIP_IDLETIME 6 int #TIP_CLICHKINT 7 int #TIP_TPORTNO 8 int #TIP_TPORTNO2 9 int #TIP_TPORTNO3 10 int #TIP_TPORTNO4 11 int #TIP_TPORTNO5 12 int #TIP_RACPORT 13 int #TIP_TMAXPORT 14 string TIP_CMPRPORT 15 string TIP_CMPRSIZE 16 int #TIP_MAXUSER 17 int TIP_TMAXDIR 18 string TIP_TMAXHOME 19 string TIP_APPDIR 20 string TIP_PATHDIR 21 string TIP_TLOGDIR 22 string TIP_SLOGDIR 23 string TIP_ULOGDIR 24 string TIP_ENVFILE 25 string #TIP_LOGINSVC 26 string #TIP_LOGOUTSVC 27 string TIP_IP 28 string #TIP_PEER 29 string TIP_TMMOPT 30 string TIP_CLHOPT 31 string #TIP_IPCPERM 32 int #TIP_MAXSVG 33 int #TIP_MAXSVR 34 int #TIP_MAXSPR 35 int #TIP_MAXTMS 36 int #TIP_MAXCPC 37 int TIP_MAXGWSVR 38 int TIP_MAXRQSVR 39 int TIP_MAXGWCPC 40 int TIP_MAXRQCPC 41 int TIP_CPORTNO 42 int TIP_REALSVR 43 string TIP_RSCPC 44 int TIP_AUTOBACKUP 45 int TIP_HOSTNAME 46 string TIP_NODETYPE 47 int TIP_CPU 48 int #TIP_MAXRSTART 49 int #TIP_GPERIOD 50 int #TIP_RESTART 51 int TIP_CURCLH 49 int TIP_LIVECTIME 50 string TIP_NODE_TMMLOGLVL 51 string TIP_NODE_CLHLOGLVL 52 string TIP_NODE_TMSLOGLVL 53 string TIP_NODE_LOGLVL 54 string TIP_NODE_MAXTHREAD 55 int TIP_EXTPORT 56 int TIP_EXTCLHPORT 57 int # # SVRGROUP section fields # # name number type flags comments *base 16000300 #TIP_NAME 0 string #TIP_NODENAME 1 string TIP_SVGTYPE 2 string #TIP_PRODNAME 3 string TIP_COUSIN 4 string TIP_BACKUP 5 string TIP_LOAD 6 int #TIP_APPDIR 7 string #TIP_ULOGDIR 8 string TIP_DBNAME 9 string TIP_OPENINFO 10 string TIP_CLOSEINFO 11 string TIP_MINTMS 12 int #TIP_MAXTMS 13 int TIP_TMSNAME 14 string #TIP_SECURITY 15 string #TIP_OWNER 16 string #TIP_ENVFILE 17 string #TIP_CPC 18 int TIP_XAOPTION 19 string TIP_SVG_TMSTYPE 20 string TIP_SVG_TMSOPT 21 string TIP_SVG_TMSTHREADS 22 int TIP_SVG_TMSLOGLVL 23 string TIP_SVG_LOGLVL 24 string TIP_NODENAME 25 string # # SERVER section fields # # name number type flags comments *base 16000350 #TIP_NAME 0 string TIP_SVGNAME 1 string #TIP_NODENAME 2 string TIP_CLOPT 3 string TIP_SEQ 4 int TIP_MIN 5 int TIP_MAX 6 int #TIP_ULOGDIR 7 string TIP_CONV 8 int TIP_MAXQCOUNT 9 int TIP_ASQCOUNT 10 int TIP_MAXRSTART 11 int TIP_GPERIOD 12 int TIP_RESTART 13 int TIP_SVRTYPE 14 string #TIP_CPC 15 int TIP_SCHEDULE 16 int #TIP_MINTHR 17 int #TIP_MAXTHR 18 int TIP_TARGET 19 string TIP_DEPEND 20 string TIP_CASCADE 21 int TIP_PROCNAME 22 string TIP_LIFESPAN 23 string TIP_DDRI 24 string TIP_CURSVR 25 int TIP_SVGNO 26 int TIP_SVR_LOGLVL 27 string # # SERVICE section fields # # name number type flags comments *base 16000400 #TIP_NAME 0 string TIP_SVRNAME 1 string TIP_PRI 2 int TIP_SVCTIME 3 int TIP_ROUTING 4 string TIP_EXPORT 5 int TIP_AUTOTRAN 6 int # # ROUTING section fields # # name number type flags comments *base 16000425 #TIP_NAME 0 string TIP_FLDTYPE 1 string TIP_RANGES 2 string TIP_SUBTYPE 3 string TIP_ELEMENT 4 string TIP_BUFTYPE 5 string TIP_OFFSET 6 int TIP_FLDLEN 7 int #TIP_FLDOFFSET 8 int # # RQ section fields # # name number type flags comments *base 16000450 #TIP_NAME 0 string #TIP_SVGNAME 1 string TIP_PRESVC 2 string TIP_QSIZE 3 int TIP_FILEPATH 4 string TIP_BOOT 5 string TIP_FSYNC 6 int TIP_BUFFERING 7 int #TIP_ENQSVC 8 int #TIP_FAILINTERVAL 9 int #TIP_FAILRETRY 10 int #TIP_FAILSVC 11 string #TIP_AFTERSVC 12 string # # GATEWAY section fields # # name number type flags comments *base 16000500 #TIP_NAME 0 string TIP_GWTYPE 1 string TIP_PORTNO 2 int #TIP_CPC 3 int TIP_RGWADDR 4 string TIP_RGWPORTNO 5 int #TIP_BACKUP 6 string #TIP_NODENAME 7 string TIP_KEY 8 string TIP_BACKUP_RGWADDR 9 string TIP_BACKUP_RGWPORTNO 10 int TIP_TIMEOUT 11 int TIP_DIRECTION 12 string TIP_MAXINRGW 13 int TIP_GWOWNER 15 string TIP_RGWOWNER 16 string TIP_RGWPASSWD 17 string # # FUNCTION section fields # # name number type flags comments *base 16000550 #TIP_NAME 0 string #TIP_SVRNAME 1 string TIP_FQSTART 2 int TIP_FQEND 3 int TIP_ENTRY 4 string # # STATISTICS segment fields # # name number type flags comments *base 16000600 #TIP_NAME 0 string TIP_STATUS 1 string TIP_STIME 2 string TIP_TTIME 3 int TIP_SVC_STIME 4 int TIP_COUNT 5 int #TIP_NO 6 int TIP_NUM_FREE 7 int TIP_NUM_REPLY 8 int TIP_NUM_FAIL 9 int TIP_NUM_REQ 10 int TIP_ENQ_REQS 11 int TIP_DEQ_REQS 12 int TIP_ENQ_REPLYS 13 int TIP_DEQ_REPLYS 14 int TIP_CLHNO 15 int TIP_SVR_NAME 16 string TIP_SVC_NAME 17 string TIP_AVERAGE 18 float TIP_QCOUNT 19 int TIP_CQCOUNT 20 int TIP_QAVERAGE 21 float TIP_MINTIME 22 float TIP_MAXTIME 23 float TIP_FAIL_COUNT 24 int TIP_ERROR_COUNT 25 int TIP_PID 26 int TIP_TOTAL_COUNT 27 int TIP_TOTAL_SVCFAIL_COUNT 28 int TIP_TOTAL_ERROR_COUNT 29 int TIP_TOTAL_AVG 30 float TIP_TOTAL_RUNNING_COUNT 31 int TIP_TMS_NAME 32 string TIP_SVG_NAME 33 string TIP_SPRI 34 int TIP_TI_THRI 35 int TIP_TI_AVG 36 float TIP_TI_XID 37 string TIP_TI_XA_STATUS 38 string TIP_GW_NAME 39 string TIP_GW_NO 40 int TIP_GW_HOSTN 41 string TIP_GW_CTYPE 42 string TIP_GW_CTYPE2 43 string TIP_GW_IPADDR 44 string TIP_GW_PORT 45 int TIP_GW_STATUS 46 string # # ADMIN segment fields # # name number type flags comments *base 16000650 TIP_IPADDR 0 string TIP_USRNAME 1 string TIP_MODULE 2 int TIP_LOGLVL 3 string TIP_SPEC 4 string # # EXTRA flag fields # # name number type flags comments *base 16000700 TIP_EXTRA_OPTION 0 int
다음은 시스템의 환경 정보를 확인하는 클라이언트 프로그램의 예제이다.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <usrinc/atmi.h> #include <usrinc/fbuf.h> #include <usrinc/tip.h> #define SEC_DOMAIN 1 #define SEC_NODE 2 #define SEC_SVGROUP 3 #define SEC_SERVER 4 #define SEC_SERVICE 5 #define SEC_ROUTING 6 #define SEC_RQ 7 #define SEC_GATEWAY 8 main(int argc, char *argv[]) { FBUF *sndbuf, *rcvbuf; TPSTART_T *tpinfo; int i, n, sect; long rcvlen; char nodename[NAMELEN]; int pid, count = 0; if (argc != 3) { printf("Usage: %s section nodename\n", argv[0]); printf("section:\n"); printf("\t1: domain\n"); printf("\t2: node\n"); printf("\t3: svrgroup\n"); printf("\t4: server\n"); printf("\t5: service\n"); printf("\t6: routing\n"); printf("\t7: rq\n"); printf("\t8: gateway\n"); exit(1); } if (!isdigit(argv[3][0])) { printf("fork count must be a digit\n"); exit(1); } count = atoi(argv[3]); sect = atoi(argv[1]); if (sect < SEC_DOMAIN || sect > SEC_GATEWAY) { printf("out of section [%d - %d]\n", SEC_DOMAIN, SEC_GATEWAY); exit(1); } strncpy(nodename, argv[2], sizeof(nodename) - 1); n = tmaxreadenv("tmax.env", "TMAX"); if (n < 0) { fprintf(stderr, "can't read env\n"); exit(1); } tpinfo = (TPSTART_T *)tpalloc("TPSTART", NULL, 0); if (tpinfo == NULL) { printf("tpalloc fail tperrno = %d\n", tperrno); exit(1); } strcpy(tpinfo->usrname, ".tpadmin"); if (tpstart((TPSTART_T *)tpinfo) == -1){ printf("tpstart fail [%s]\n", tpstrerror(tperrno)); exit(1); } if ((sndbuf = (FBUF *)tpalloc("FIELD", NULL, 0)) == NULL) { printf("tpalloc failed! errno = %d\n", tperrno); tpend(); exit(1); } if ((rcvbuf = (FBUF *)tpalloc("FIELD", NULL, 0)) == NULL) { printf("tpalloc failed! errno = %d\n", tperrno); tpend(); exit(1); } n = fbput(sndbuf, TIP_OPERATION, "GET", 0); n = fbput(sndbuf, TIP_SEGMENT, "CONFIGURATION", 0); switch (sect) { case SEC_DOMAIN: n = fbput(sndbuf, TIP_SECTION, "DOMAIN", 0); break; case SEC_NODE: n = fbput(sndbuf, TIP_SECTION, "NODE", 0); break; case SEC_SVGROUP: n = fbput(sndbuf, TIP_SECTION, "SVGROUP", 0); break; case SEC_SERVER: n = fbput(sndbuf, TIP_SECTION, "SERVER", 0); break; case SEC_SERVICE: n = fbput(sndbuf, TIP_SECTION, "SERVICE", 0); break; case SEC_ROUTING: n = fbput(sndbuf, TIP_SECTION, "ROUTING", 0); break; case SEC_RQ: n = fbput(sndbuf, TIP_SECTION, "RQ", 0); break; case SEC_GATEWAY: n = fbput(sndbuf, TIP_SECTION, "GATEWAY", 0); break; } n = fbput(sndbuf, TIP_NODENAME, nodename, 0); n = tpcall("TIPSVC", (char *)sndbuf, 0, (char **)&rcvbuf, &rcvlen, TPNOFLAGS); if (n < 0) { printf("tpcall fail [%s]\n", tpstrerror(tperrno)); fbprint(rcvbuf); tpfree((char *)sndbuf); tpfree((char *)rcvbuf); tpend(); exit(1); } #if 1 fbprint(rcvbuf); #endif tpfree((char *)sndbuf); tpfree((char *)rcvbuf); tpend(); }
[결과]
다음은 해당 프로그램의 결과(Domain Conf)이다.
$ client 1 tmaxh4 fkey = 217326601, fname = TIP_ERROR, type = int, value = 0 ... fkey = 485762214, fname = TIP_CRYPT, type = string, value = NO fkey = 485762215, fname = TIP_DOMAIN_TMMLOGLVL, type = string, value = DEBUG1 fkey = 485762216, fname = TIP_DOMAIN_CLHLOGLVL, type = string, value = DEBUG2 fkey = 485762217, fname = TIP_DOMAIN_TMSLOGLVL, type = string, value = DEBUG3 fkey = 485762218, fname = TIP_DOMAIN_LOGLVL, type = string, value = DEBUG4 fkey = 217326763, fname = TIP_DOMAIN_MAXTHREAD, type = int, value = 128
다음은 시스템의 통계 정보를 확인하는 프로그램의 예제이다.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <usrinc/atmi.h> #include <usrinc/fbuf.h> #include <usrinc/tip.h> #define SEC_NODE 1 #define SEC_TPROC 2 #define SEC_SPR 3 #define SEC_SERVICE 4 #define SEC_RQ 5 #define SEC_TMS 6 #define SEC_TMMS 7 #define SEC_CLHS 8 #define NODE_NAME_SIZE 32 main(int argc, char *argv[]) { FBUF *sndbuf, *rcvbuf; TPSTART_T *tpinfo; int i, n, sect; long rcvlen; char nodename[NODE_NAME_SIZE]; int stat; if (argc != 3) { printf("Usage: %s section node\n", argv[0]); printf("section:\n"); printf("\t1: node\n"); printf("\t2: tproc\n"); printf("\t3: spr\n"); printf("\t4: service\n"); printf("\t5: rq\n"); printf("\t6: tms\n"); printf("\t7: tmms\n"); printf("\t8: clhs\n"); exit(1); } sect = atoi(argv[1]); if (sect < SEC_NODE || sect > SEC_CLHS) { printf("out of section [%d - %d]\n",SEC_NODE, SEC_TMMS); exit(1); } memset(nodename, 0x00, NODE_NAME_SIZE); strncpy(nodename, argv[2], NODE_NAME_SIZE - 1); n = tmaxreadenv("tmax.env", "TMAX"); if (n < 0) { fprintf(stderr, "can't read env\n"); exit(1); } tpinfo = (TPSTART_T *)tpalloc("TPSTART", NULL, 0); if (tpinfo == NULL) { printf("tpalloc fail tperrno = %d\n", tperrno); exit(1); } strcpy(tpinfo->dompwd, "xamt123"); if (tpstart((TPSTART_T *)tpinfo) == -1){ printf("tpstart fail tperrno = %d\n", tperrno); exit(1); } if ((sndbuf = (FBUF *)tpalloc("FIELD", NULL, 0)) == NULL) { printf("tpalloc failed! errno = %d\n", tperrno); tpend(); exit(1); } if ((rcvbuf = (FBUF *)tpalloc("FIELD", NULL, 0)) == NULL) { printf("tpalloc failed! errno = %d\n", tperrno); tpend(); exit(1); } n = fbput(sndbuf, TIP_OPERATION, "GET", 0); n = fbput(sndbuf, TIP_SEGMENT, "STATISTICS", 0); switch (sect) { case SEC_NODE: n = fbput(sndbuf, TIP_SECTION, "NODE", 0); break; case SEC_TPROC: n = fbput(sndbuf, TIP_SECTION, "TPROC", 0); break; case SEC_SPR: n = fbput(sndbuf, TIP_SECTION, "SPR", 0); break; case SEC_SERVICE: n = fbput(sndbuf, TIP_SECTION, "SERVICE", 0); break; case SEC_RQ: n = fbput(sndbuf, TIP_SECTION, "RQ", 0); break; case SEC_TMS: stat = 1; n = fbput(sndbuf, TIP_SECTION, "TMS", 0); n = fbput(sndbuf, TIP_EXTRA_OPTION, (char *)&stat, 0); break; case SEC_TMMS: n = fbput(sndbuf, TIP_SECTION, "TMMS", 0); break; case SEC_CLHS: n = fbput(sndbuf, TIP_SECTION, "CLHS", 0); break; } n = fbput(sndbuf, TIP_NODENAME, nodename, 0); n = tpcall("TIPSVC", (char *)sndbuf, 0, (char **)&rcvbuf, &rcvlen, TPNOFLAGS); if (n < 0) { printf("tpcall fail [%s]\n", tpstrerror(tperrno)); fbprint(rcvbuf); tpfree((char *)sndbuf); tpfree((char *)rcvbuf); tpend(); exit(1); } fbprint(rcvbuf); tpfree((char *)sndbuf); tpfree((char *)rcvbuf); tpend(); }
[결과]
다음은 해당 프로그램의 결과(TMS STATISTICS)를 나타내는 예제이다.
$ client 3000 1 2 fkey = 217326601, fname = TIP_ERROR, type = int, value = 0 fkey = 485762680, fname = TIP_TMS_NAME, type = string, value = tms_ora2 fkey = 485762681, fname = TIP_SVG_NAME, type = string, value = xa1 fkey = 217327226, fname = TIP_SPRI, type = int, value = 0 fkey = 485762649, fname = TIP_STATUS, type = string, value = RUN fkey = 217327197, fname = TIP_COUNT, type = int, value = 0 fkey = 351544938, fname = TIP_AVERAGE, type = float, value = 0.000000 fkey = 217327212, fname = TIP_CQCOUNT, type = int, value = 0 fkey = 217327227, fname = TIP_TI_THRI, type = int, value = 1 fkey = 351544956, fname = TIP_TI_AVG, type = float, value = 0.000000 fkey = 485762685, fname = TIP_TI_XID, type = string, value = 00000013664 fkey = 485762686, fname = TIP_TI_XA_STATUS, type = string, value = COMMIT
다음은 서버 프로세스를 추가로 기동하거나 종료하는 프로그램 예제이다.
< cli.c >
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <usrinc/atmi.h> #include <usrinc/fbuf.h> #include <usrinc/tmaxapi.h> #include <usrinc/tip.h> #define NODE_NAME_SIZE 32 main(int argc, char *argv[]) { FBUF *sndbuf, *rcvbuf; TPSTART_T *tpinfo; int i, n, type, clid, count, flags; long rcvlen; char svrname[TMAX_NAME_SIZE]; char svgname[TMAX_NAME_SIZE]; char nodename[NODE_NAME_SIZE]; int pid, forkcnt; if (argc != 6) { printf("Usage: %s type svrname count nodename forkcnt\n", argv[0]) ; printf("type 1: BOOT, 2: DOWN, 3: DISCON\n"); exit(1); } type = atoi(argv[1]); if ((type != 1) && (type != 2) && (type != 3)) { printf("couldn't support such a type %d\n", type); exit(1); } if (strlen(argv[2]) >= TMAX_NAME_SIZE) { printf("too large name [%s]\n", argv[1]); exit(1); } strcpy(svrname, argv[2]); count = atoi(argv[3]); flags = 0; strncpy(nodename, argv[4], NODE_NAME_SIZE - 1); forkcnt = atoi(argv[5]); n = tmaxreadenv("tmax.env", "TMAX"); if (n < 0) { fprintf(stderr, "can't read env\n"); exit(1); } tpinfo = (TPSTART_T *)tpalloc("TPSTART", NULL, 0); if (tpinfo == NULL) { printf("tpalloc fail tperrno = %d\n", tperrno); exit(1); } strcpy(tpinfo->usrname, ".tpadmin"); for (i = 1; i < forkcnt; i++) { if ((pid = fork()) < 0) exit(1); else if (pid == 0) break; } if (tpstart((TPSTART_T *)tpinfo) == -1){ printf("tpstart fail tperrno = %d\n", tperrno); exit(1); } if ((sndbuf = (FBUF *)tpalloc("FIELD", NULL, 0)) == NULL) { printf("tpalloc failed! errno = %d\n", tperrno); tpend(); exit(1); } if ((rcvbuf = (FBUF *)tpalloc("FIELD", NULL, 0)) == NULL) { printf("tpalloc failed! errno = %d\n", tperrno); tpend(); exit(1); } n = fbput(sndbuf, TIP_OPERATION, "GET", 0); n = fbput(sndbuf, TIP_SEGMENT, "ADMINISTRATION", 0); if (type == 1) n = fbput(sndbuf, TIP_CMD, "BOOT", 0); else if (type == 2) n = fbput(sndbuf, TIP_CMD, "DOWN", 0); else n = fbput(sndbuf, TIP_CMD, "DISCON", 0); if (type == 3) { clid = count; /* at type 3 */ flags |= TIP_SFLAG; n = fbput(sndbuf, TIP_CLID, (char *)&clid, 0); n = fbput(sndbuf, TIP_FLAGS, (char *)&flags, 0); } else { flags |= TIP_SFLAG; n = fbput(sndbuf, TIP_SVRNAME, svrname, 0); n = fbput(sndbuf, TIP_COUNT, (char *)&count, 0); n = fbput(sndbuf, TIP_FLAGS, (char *)&flags, 0); } n = fbput(sndbuf, TIP_NODENAME, nodename, 0); n = tpcall("TIPSVC", (char *)sndbuf, 0, (char **)&rcvbuf, &rcvlen, TPNOFLAGS); if (n < 0) { printf("tpcall failed! errno = %d[%s]\n", tperrno, tpstrerror(tperrno)); fbprint(rcvbuf); tpfree((char *)sndbuf); tpfree((char *)rcvbuf); tpend(); exit(1); } fbprint(rcvbuf); tpfree((char *)sndbuf); tpfree((char *)rcvbuf); tpend();
다음은 svr23_stat_ins 이라는 서버의 log level을 debug4로 변경하는 예제이다.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <usrinc/atmi.h> #include <usrinc/fbuf.h> #include <usrinc/tmaxapi.h> #include <usrinc/tip.h> #include "../fdl/tip_fdl.h" #define NFLAG 32 #define GFLAG 8 #define VFLAG 1024 int case_chlog(int, char *[], FBUF *); #define NODE_NAME_SIZE 32 main(int argc, char *argv[]) { FBUF *sndbuf, *rcvbuf; TPSTART_T *tpinfo; int i, ret, n, type, clid, count, flags = 0; long rcvlen; char svrname[TMAX_NAME_SIZE]; char svgname[TMAX_NAME_SIZE]; char nodename[NODE_NAME_SIZE]; int pid, forkcnt; if (argc < 6) { printf("Usage: %s svgname svrname nodename [chlogmodule] [flags] [loglvl]\n", argv[0]); printf("chlogmodule 1: TIP_TMM, 2: TIP_CLH, 4: TIP_TMS, 8: TIP_SVR\n"); printf("flags 1: NFLAGS, 2: GFLAGS, 3: VFLAGS\n"); printf("loglvl : 1: compact, 2: basic, 3: detail, 4: debug1, 5: debug2, 6: debug3, 7: debug4\n"); exit(1); } n = tmaxreadenv("tmax.env", "TMAX"); if (n < 0) { fprintf(stderr, "can't read env\n"); exit(1); } tpinfo = (TPSTART_T *)tpalloc("TPSTART", NULL, 0); if (tpinfo == NULL) { printf("tpalloc fail tperrno = %d\n", tperrno); exit(1); } strcpy(tpinfo->usrname, ".tpadmin"); strcpy(svgname, argv[1]); strcpy(svrname, argv[2]); strncpy(nodename, argv[3], NODE_NAME_SIZE - 1); if (tpstart((TPSTART_T *)tpinfo) == -1){ printf("tpstart fail tperrno = %d\n", tperrno); exit(1); } if ((sndbuf = (FBUF *)tpalloc("FIELD", NULL, 0)) == NULL) { printf("tpalloc failed! errno = %d\n", tperrno); tpend(); exit(1); } if ((rcvbuf = (FBUF *)tpalloc("FIELD", NULL, 0)) == NULL) { printf("tpalloc failed! errno = %d\n", tperrno); tpend(); exit(1); } ret = case_chlog(argc, argv, sndbuf); n = fbput(sndbuf, TIP_OPERATION, "GET", 0); n = fbput(sndbuf, TIP_SEGMENT, "ADMINISTRATION", 0); n = fbput(sndbuf, TIP_CMD, "CHLOG", 0); n = fbput(sndbuf, TIP_NODENAME, nodename, 0); n = fbput(sndbuf, TIP_SVGNAME, svgname , 0); n = fbput(sndbuf, TIP_SVRNAME, svrname, 0); n=tpcall("TIPSVC", (char *)sndbuf, 0, (char **)&rcvbuf, &rcvlen, TPNOFLAGS); if (n < 0) { printf("tpcall failed! errno = %d[%s]\n", tperrno, tpstrerror(tperrno)); fbprint(rcvbuf); tpfree((char *)sndbuf); tpfree((char *)rcvbuf); tpend(); exit(1); } fbprint(rcvbuf); tpfree((char *)sndbuf); tpfree((char *)rcvbuf); tpend(); } int case_chlog(int argc2, char *argv2[], FBUF *sndbuf) { int chlogmdl, loglvl, flags, n=0; char cloglvl[TMAX_NAME_SIZE]; const int true = 1, false = 0; chlogmdl = atoi(argv2[4]); if( (chlogmdl != 1) && (chlogmdl != 2) && (chlogmdl != 4) && (chlogmdl != 8) { printf("couldn't support such a chlogmdl\n"); exit(1); } flags = atoi(argv2[5]); if( (flags != NFLAG) && (flags != GFLAG) && (flags != VFLAG) ) { printf("couldn't support such a flags\n"); exit(1); } loglvl = atoi(argv2[6]); if( (loglvl < 1) || (loglvl > 7) ) { printf("couldn't support such a loglvl\n"); exit(1); } switch (loglvl) { case 1 : strcpy(cloglvl, "compact"); break; case 2 : strcpy(cloglvl, "basic"); break; case 3 : strcpy(cloglvl, "detail"); break; case 4 : strcpy(cloglvl, "debug1"); break; case 5 : strcpy(cloglvl, "debug2"); break; case 6 : strcpy(cloglvl, "debug3"); break; case 7 : strcpy(cloglvl, "debug4"); break; } n = fbput(sndbuf, TIP_MODULE, (char *)&chlogmdl, 0); n = fbput(sndbuf, TIP_FLAGS, (char *)&flags , 0); n = fbput(sndbuf, TIP_LOGLVL, cloglvl , 0); return 1; }
[결과] (TIP_SVR, => DEBUG4)
$ client xa1 svr23_stat_ins $HOSTNAME 8 1024 7 fkey = 217326601, fname = TIP_ERROR, type = int, value = 0 >>> tmadmin (cfg -v) loglvl = DEBUG4
서버에서 tpcall()을 수행할 경우 같은 서버에 존재하는 서비스일 경우에도 내부에서 Recursive하게 호출할 수 있도록 기능이 추가되었다. 이는 서버에서 Multicontext 기법을 통해 tpcall()에 한해서 Local Recursive call이 가능하도록 한 것으로, 무한 loop를 방지하기 위해서 최대 depth는 8로 제한한다.
Local Recursive call을 사용하기 위해서는 서버 프로그램을 컴파일할 때 반드시 CFLAGS에 –D_MCONTEXT를 추가해야 하며, libsvr.so 대신 libsvrmc.so 서버 라이브러리를 이용해 컴파일해야 한다.
다음은 서버 프로그램의 예제이다.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <usrinc/atmi.h> SVC15004_1(TPSVCINFO *msg) { int i; char *rcvbuf; long rcvlen; if ((rcvbuf = (char *)tpalloc("STRING", NULL, 0)) == NULL) printf("rcvbuf tpalloc fail[%s]\n",tpstrerror(tperrno)); if (tpcall("SVC15004_2", msg->data, 0, &rcvbuf, &rcvlen, 0) == -1) { printf("tpcall fail [%s]\n", tpstrerror(tperrno)); tpfree((char *)rcvbuf); tpreturn(TPFAIL, 0, 0, 0, 0); } strcat(rcvbuf, "_Success"); tpreturn(TPSUCCESS,0,(char *)rcvbuf, 0,0); } SVC15004_2(TPSVCINFO *msg) { int i; char *rcvbuf; long rcvlen; if ((rcvbuf = (char *)tpalloc("STRING", NULL, 0)) == NULL) printf("rcvbuf tpalloc fail \n"); } if (tpcall("SVC15004_3", msg->data, 0, &rcvbuf, &rcvlen, 0) == -1) { printf("tpcall fail [%s]\n", tpstrerror(tperrno)); tpfree((char *)rcvbuf); tpreturn(TPFAIL, 0, 0, 0, 0); } strcat(rcvbuf, "_Success"); tpreturn(TPSUCCESS,0,(char *)rcvbuf, 0,0); } SVC15004_3(TPSVCINFO *msg) { int i; char *rcvbuf; long rcvlen; if ((rcvbuf = (char *)tpalloc("STRING", NULL, 0)) == NULL) printf("rcvbuf tpalloc fail \n"); if (tpcall("SVC15004_4", msg->data, 0, &rcvbuf, &rcvlen, 0) == -1) { printf("tpcall fail [%s]\n", tpstrerror(tperrno)); tpfree((char *)rcvbuf); tpreturn(TPFAIL, 0, 0, 0, 0); } strcat(rcvbuf, "_Success"); tpreturn(TPSUCCESS,0,(char *)rcvbuf, 0,0); }
다음은 Makefile의 예제이다.
<Makefile.c.mc>
# Server makefile TARGET = $(COMP_TARGET) APOBJS = $(TARGET).o NSDLOBJ = $(TMAXDIR)/lib64/sdl.o LIBS = -lsvrmc -lnodb OBJS = $(APOBJS) $(SVCTOBJ) SVCTOBJ = $(TARGET)_svctab.o CFLAGS = -O -Ae -w +DSblended +DD64 -D_HP -I$(TMAXDIR) -D_MCONTEXT APPDIR = $(TMAXDIR)/appbin SVCTDIR = $(TMAXDIR)/svct LIBDIR = $(TMAXDIR)/lib64 # .SUFFIXES : .c .c.o: $(CC) $(CFLAGS) -c $< # # server compile # $(TARGET): $(OBJS) $(CC) $(CFLAGS) -L$(LIBDIR) -o $(TARGET) $(OBJS) $(LIBS) $(NSDLOBJ) mv $(TARGET) $(APPDIR)/. rm -f $(OBJS) $(APOBJS): $(TARGET).c $(CC) $(CFLAGS) -c $(TARGET).c $(SVCTOBJ): cp -f $(SVCTDIR)/$(TARGET)_svctab.c . touch ./$(TARGET)_svctab.c $(CC) $(CFLAGS) -c ./$(TARGET)_svctab.c # clean: -rm -f *.o core $(APPDIR)/$(TARGET)