본 장에서는 Tmax 서버에서 사용하는 함수에 대해 설명한다. ATMI에서 서버 프로그램을 작성할 때 필요한 함수에 대해 알아본다. 서버 또한 클라이언트 역할도 할 수 있기때문에 클라이언트에서 사용하는 함수도 사용이 가능하다.
TCS 방식의 서버 프로그램에서 사용하는 함수에 대해 설명한다.
서비스 완료 관련 함수
tpreturn()은 클라이언트에게 응답을 보내는 것이며, tpforward()는 필요에 의해 또 다른 서버로 서비스 요청을 보내고 서비스를 종료한다.
서버 초기화와 종료 관련 함수
애플리케이션과 연결할 데이터베이스의 open과 close를 담당하고, 명령어 라인 옵션 처리 등의 기능을 제공한다. 이 서브 루틴을 개발자가 작성하지 않으면 Tmax에서 기본적으로 제공된다.
Multithread/Multicontext
함수 | 설명 |
---|---|
tpsvrthrinit | STD_MT 타입의 서버에서 서비스 스레드들이 생성될 때 각각의 스레드마다 고유한 초기화 작업을 수행할 수 있도록 초기화 함수를 제공한다. Tmax v5.0 SP2 이상에서 지원한다. |
tpsvrthrdone | STD_MT 타입의 서버에서 서비스 스레드가 종료될 때 이 함수를 호출한다. Tmax v5.0 SP2 이상에서 지원한다. |
tpgetctxt | 함수를 호출하는 스레드에 현재 설정되어 있는 컨텍스트의 ID를 첫 번째 파라미터로 반환한다. |
tpsetctxt | 함수를 호출하는 스레드의 컨택스트를 첫 번째 파라미터의 ID로 설정한다. |
비요청 관련 함수
Tmax에서 서버는 클라이언트가 요청하지 않은 메시지를 클라이언트에게 일방적으로 보낼 수 있다. 이것은 Tmax에 접속되어 있는 클라이언트에게 알리고 싶은 메시지를 전달하는 경우 사용한다. 비요청 메시지를 받을 수 있는 클라이언트는 Tmax에 접속되어 있어야 하고, Tmax에 접속해서 비요청 메시지를 받으려고 하는 경우 flags 값을 설정해야 한다.
함수 | 설명 |
---|---|
tpsendtocli | 클라이언트의 요청이 없더라도 서버에서 클라이언트가 사전 등록한 요구 메시지를 자동으로 송신한다. |
tpgetclid | Tmax 시스템에 접속한 클라이언트의 ID를 반환한다. ID는 tpsendtocil()에 사용된다. |
tpchkclid | 해당 서버 프로세스가 위치한 노드의 클라이언트 ID에 해당하는 클라이언트가 접속해 있는지 검사한다. |
각 함수의 관련 함수에 대한 자세한 사항은 "Tmax Reference Guide"를 참고한다.
서버 프로그램은 Tmax에서 제공하는 main()과 서비스 루틴으로 구성된다. main()은 데이터베이스 연결 및 해제, 명령어 라인 옵션 처리 등의 역할을 하는 루틴으로 구성되어 있으며, 서비스 루틴은 실제로 클라이언트의 요청을 받아 업무를 처리하는 루틴으로 구성되어 있다.
서버 main()은 클라이언트 요청을 받아서 해당 서비스 루틴을 TPSVCINFO 구조체로 호출하여 요청을 처리하게 한다. TPSVCINFO 구조체는 서비스를 요청한 클라이언트에 대한 정보와 처리할 데이터 정보를 가지고 있다.
TPSVCINFO 구조체는 atmi.h 헤더 파일에 선언되어 있으며 구성요소는 다음과 같다.
#define XATMI_SERVICE_NAME_LENGTH 16 struct tpsvcinfo { char name[XATMI_SERVICE_NAME_LENGTH]; /* 요청된 서비스명 */ char *data; /* 요청 데이터 */ long len; /* 요청 데이터 길이 */ long flags; /* 서비스 속성 */ Int cd; /* 연결 구별자 */ }; typedef struct tpsvcinfo TPSVCINFO
멤버 | 설명 |
---|---|
name | 클라이언트에서 요청한 서비스 루틴명이다. |
data | 클라이언트가 요청 데이터를 받기 위해서 사용되는 버퍼로, 서버 main() 안에서 tpalloc()으로 미리 할당된다. |
len | 요청한 데이터의 길이를 나타낸다. |
flags | 트랜잭션 상태에 있는지 또는 호출자가 반드시 응답을 요구하는지 등을 서비스에게 알려준다. 예를 들어 flags가 TPTRAN이면 서비스가 트랜잭션 모드 안에 있다는 것이고, TPNOTRAN이면 현재의 트랜잭션에 참여할 수 있다는 것을 나타낸다. |
cd | 연결 구별자로, 어떤 클라이언트에게 응답을 보내야 할지를 설정한다. 서버는 클라이언트가 요청한 서비스를 처리하기 위해 미리 버퍼를 main()에서 할당하기 때문에 tpreturn() , tpforward()로 통신할 때 TPSVCINFO의 데이터를 사용할 것을 권장한다. TPSVCINFO의 데이터에 접근할 때, 서버 프로그램과 클라이언트 프로그램의 버퍼 유형이 같아야 한다. |
클라이언트 프로그램
다음은 클라이언트 프로그램 프로그램에 대한 예이다.
#include <usrinc/atmi.h> . . . main() { struct strdata *cltdata; if ((cltdata = (strcut strdata *)tpalloc(“STRUCT”, “strdata”, sizeof(struct strdata)) ) == NULL){ error processing routine } . . . if ((tpcall (“SEL_SVC”, cltdata, 0, (char **)&cltdata, &len, TPNOFLAGS))== -1){ error processing routine } . . . }
서버 프로그램
다음은 서버 프로그램에 대한 예로 개발자가 작성한 서비스 루틴이다. main()은 Tmax에서 제공한 것이다.
#include <usrinc/atmi.h> . . . SEL_SVC(TPSVCINFO *msg) /* 클라이언트와 클라이언트의 요청 내용이 포함된 구조체*/ { struct strdata *svcdata; /* 버퍼 유형과 일치하도록 데이터형을 변환 */ svcdata = (struct strdata *)msg->data; . . . svcdata->ip = sip; strcpy(msg ->data, svcdata); tpreturn(TPSUCCESS, 0, msg->data, sizeof(struct strdata), TPNOFLAGS); };
서버의 서비스를 종료하는 함수로, 서비스 루틴의 완료를 의미한다. C 언어에서의 반환 문장과 같은 역할을 한다. tpreturn()이 호출되면 서비스 루틴은 Tmax 시스템에게 반환된다. Tmax 시스템으로 정상적으로 반환되기 위해서는 tpreturn()은 Tmax 시스템이 제어하는 서비스 루틴 내에서 호출되는 것이 바람직하다.
tpreturn() 함수는 서비스의 응답 메시지를 송신한다. 응답을 수신할 프로그램이 tpcall(), tpgetrply(), tprecv()로 응답을 기다리고 있다면 그 응답은 tpreturn() 호출이 성공한 후 수신자의 버퍼를 통해 전달된다.
tpreturn()은 대화형 서비스들이 대화형 연결을 종료할 수 있게 한다. 서비스 루틴은 직접 tpdiscon()을 호출할 수 없다. 올바른 결과를 보장하려면 대화형 서비스에 연결된 프로그램은 tpdiscon()을 호출하지 않는 것이 좋다. 그보다 대화형 서비스에서의 완료 통보 즉, tpreturn() 함수를 사용하여 송신되는 TPEV_SVCSUCC나 TPEV_SVCFAIL과 같은 이벤트들을 기다려야 한다.
서비스 루틴이 트랜잭션 모드에 있는데 해당 서비스를 호출한 클라이언트나 서비스가 명시적으로 트랜잭션을 시작하지 않으면(tx_begin을 사용하지 않으면) tpreturn은 트랜잭션의 한 부분으로서 TPSUCCESS인 경우 commit 또는 Rollback된다. 서비스는 동일한 트랜잭션(global transaction)의 한 부분으로서 여러 번 호출될 수도 있다. 그래서 tx_begin을 사용한 트랜잭션 시작자가 tx_commit 또는 tx_rollback 중 하나를 호출하여 트랜잭션을 완료하기 전까지는 완전히 commit 또는 Rollback되지 않는다.
tpreturn() 함수는 서비스 루틴에서 요청된 서비스들로부터 모든 응답을 수신한 후에 호출되어야 한다. 그렇지 않으면 서비스 특성에 따라 [TPESVCERR] 에러나 TPEV_SVCERR 이벤트가 서비스 루틴과 통신하는 프로그램에게 반환된다. 수신되지 않은 응답들은 Tmax 시스템에 의해 자동으로 무시된다. 또한 이런 응답들에 사용되는 구별자(descriptor)들은 무효화된다.
tpreturn() 함수는 대화형 통신에 사용되는 서비스에서 시작된 모든 연결을 종료한 후에 호출되어야 한다. 그렇지 않으면 서비스 특성에 따라 [TPESVCERR] 에러나 TPEV_SVCERR 이벤트 중의 하나가 서비스 루틴과 통신하는 프로그램에게 반환된다. 또한 강제적인 연결 해제 이벤트(TPEV_DISCONIMM)가 서비스와 연결된 모든 연결 종속자들에게 전달된다.
대화형 통신에서 서비스 루틴이 tpreturn()을 호출할 때 통신 제어권을 가지고 있지 않았다면 2가지 결과가 발생할 수 있다.
서비스 루틴이 TPFAIL의 rval과 NULL의 data로 tpreturn()를 호출하였다면 대화 시작자에게 TPEV_SVCFAIL 이벤트가 전달된다.
이와 다른 형태의 tpreturn()이 호출된다면 대화 시작자에게 TPEV_SVCERR 이벤트가 전달된다. 대화형 서비스는 서비스에서 시작하지 않은 대화형 연결을 하나만 가지고 있기 때문에, Tmax 시스템에서 데이터나 이벤트가 송신되어야 할 구별자를 알고 있다. 따라서 구별자(descriptor)는 tpreturn()에 파라미터로 전달되지 않는다.
프로토타입
# include <atmi.h> void tpreturn (int rval, long rcode, char *data, long len, long flags)
파라미터
파라미터 | 설명 |
---|---|
rval | rval에 설정 가능한 값은 표 이후에 설명한다. 설명에 존재하지 않는 rval 값은 모두 TPFAIL로 간주된다. |
rcode | 애플리케이션에서 사용자에 의해 정의되는 반환값 rcode는 서비스 응답을 수신하는 프로그램에게 송신된다. 이 코드는 rval의 값과 상관없이 응답이 클라이언트로 무사히 송신될 수 있는 한(수신하는 호출이 성공하거나 [TPSVCFAIL]로 반환하거나 또는 TPEV_SVCSUCC 또는 TPEV_SVCFAIL 이벤트들 중 하나를 수신하는 한) 송신된다. rcode 값은 수신자에게 전역변수 tpurcode로 전달된다. |
data | 송신되는 응답 데이터를 가리킨다. data가 NULL이 아니라면 반드시 이전에 tpalloc()에 의하여 할당된 버퍼를 가리켜야 한다. 이것이 서비스 루틴에 전달된 것과 동일한 버퍼라면 Tmax 시스템에서 처리를 담당한다. 따라서 서비스 루틴 작성자는 이 버퍼에 대한 제거 여부를 신경 쓸 필요가 없다. 실제로 사용자가 이 버퍼를 제거하려 한다면 이는 실패한다. 그러나 tpreturn()으로 전달되는 버퍼가 서비스가 발생할 때와 동일한 버퍼가 아니라면 tpreturn()은 이 버퍼를 해제한다. |
len | 송신된 데이터 길이이다. data가 길이 명시가 필요 없는 버퍼를 가리킨다면 len은 무시되고 보통 0이 사용된다. data가 길이 명시가 필요한 버퍼를 가리킨다면 len은 0이 될 수 없다. data가 NULL이면 len은 무시된다. 이 경우, 서비스를 호출한 프로그램이 응답을 기대하고 있다면, 아무 데이터도 없는 응답이 송신된다. 응답이 기대되지 않는다면 tpreturn()은 필요에 따라 data를 제거하고, 송신하는 응답 없이 반환한다. |
flags | 사용되지 않으며 반드시 0으로 설정하도록 한다. 서비스가 대화형이라면 데이터가 전달되지 않는 경우는 다음의 2가지이다. tpreturn()를 호출할 경우에 대화형 연결이 이미 종료된 경우로 호출자가 TPEV_DISCONIMM 이벤트를 수신하였다. 이 경우 tpreturn()은 단순히 서비스 루틴을 종료하고, 트랜잭션 모드에 있다면 현재 트랜잭션을 Rollback한다. 이 경우 호출자의 데이터는 전달될 수 없다. 호출자가 통신 제어권을 갖고 있지 않다면 위에서 언급한 것처럼 TPEV_SVCFAIL 또는 TPEV_SVCERR 중 하나가 대화 시작자에게 송신된다. 대화 시작자가 수신하는 이벤트에 관계없이 어떤 데이터도 전달되지 않는다. 그러나 대화 시작자가 TPEV_SVCFAIL 이벤트를 수신하였다면 반환 코드는 시작자의 tpurcode 변수로 이용 가능하다. |
다음은 rval로 사용 가능한 값이다.
rval 값 | 설명 |
---|---|
TPSUCCESS | 서비스가 성공적으로 종료되었다. 데이터가 존재하고 tpreturn() 수행 중에 에러가 발생하지 않는다면 데이터는 송신된다. 호출자가 트랜잭션 모드에 있다면 이 트랜잭션의 한 부분을 commit이 가능한 상태로 결정한다. 트랜잭션이 최종적으로 완료될 때, 그 트랜잭션에 속한 나머지 서비스들이 모두 성공적으로 완료되어 commit이 가능한 상태라면 commit을 하고, 하나라도 실패하면 Rollback된다. tpreturn()에 대한 호출이 반드시 전체 트랜잭션을 완료하는 것이 아님에 유의해야 한다. 또한 호출자가 TPSUCCESS로 반환하더라도 대기 중인 응답이나 대화형 연결이 존재하거나 혹은 서비스 내에서 행해진 어떤 작업이 트랜잭션을 Rollback되도록 했다면 서비스 실패로 메시지가 송신된다. 응답의 수신자가 [TPESVCERR] 표시 또는 TPEV_SVCERR 이벤트를 수신한다. 서비스 루틴 내에서 트랜잭션이 Rollback되면 rval은 TPFAIL로 설정됨에 유의해야 한다. 대화형 서비스에서 TPSUCCESS로 반환되면 TPEV_SVCSUCC 이벤트가 발생된다. |
TPFAIL | 서비스가 애플리케이션의 실패로 종료되었다. 응답을 수신하는 프로그램에 에러가 반환된다. 응답을 수신하는 호출이 실패하고 수신자는 [TPSVCFAIL] 값이나 TPEV_SVCFAIL 이벤트를 수신한다. 이 값은 데이터를 송신할 수 없다. TPFAIL 호출자가 트랜잭션 모드에 있고 autotransaction인 경우 tpreturn()은 트랜잭션을 Rollback한다. 트랜잭션이 이미 Rollback 상태로 결정되어 있을 수도 있다. |
TPEXIT | 서비스 호출 후 반환할 경우 서버 프로세스를 강제 종료하고자 할 때 사용된다. tpexit()로 종료된 프로세스는 TMM에 의해 다시 시동된다. |
TPDOWN | TPEXIT와 비슷하나 TPDOWN으로 종료된 프로세스는 TMM에 의해 다시 기동되지 않는다. |
TMSUCCESS | TPSUCCESS와 동일하다. |
TMFAIL | TPFAIL과 동일하다. |
반환값
서비스 루틴은 호출자인 Tmax 시스템에게 어떤 값도 반환하지 않는다. 서비스 루틴은 tpreturn()을 사용하여 종료되는 것이 원칙이다. 서비스 루틴이 tpreturn()을 사용하지 않고 예를 들어, C 언어의 반환 문장 등을 사용하여 반환한다면 서버는 서비스 요청자에게 서비스 에러를 반환한다. 대화형 통신을 위해 유지되어 있는 연결이 강제적으로 종료되고, 비동기적으로 기다리고 있는 응답들이 모두 무시된다.
서버가 트랜잭션 모드에 있었다면 그 트랜잭션은 Rollback된다. 또한 tpreturn()이 서비스 루틴 외부에서 사용되었을 경우(예를 들어 서비스가 아닌 루틴에서 사용된 경우) 이는 아무런 일도 하지 않고 단순히 반환만 한다.
오류
tpreturn()이 서비스 루틴을 종료시키기 때문에 파라미터를 처리하는 중에 에러가 발생하면 호출자인 서비스 루틴에게 전달되지 않는다. 에러들은 다음과 같이 전달된다.
구분 | 설명 |
---|---|
동기와 비동기 통신 | tpcall() 또는 tpgetrply()으로 서비스 결과를 수신하는 프로그램에 대해서는 tperrno에 [TPESVCERR]이 전달된다. |
대화형 통신 | tpsend()나 tprecv()를 사용하는 프로그램에 대해서는 TPEV_SVCERR 이벤트를 발생시킨다. |
예제
#include <stdio.h> #include <usrinc/atmi.h> SERVICE1(TPSVCINFO *msg) { char *buf; long len; buf=tpalloc(“STRING”, NULL, 0); if (buf==NULL) { error processsing } buf=msg->data; data process.... ret=tpcall(“SERVICE2”, buf, sizeof(buf), &buf, &len, TPNOFLAGS); if (ret==-1) { error processing } data process.... if (buf !=”SUCCESS”) { printf(“svc fail..\n”); tpreturn (TPFAIL, -1, NULL,0,0); } else { tpreturn(TPSUCCESS, 0, msg->data, msg->len, 0); } }
관련 함수
tpalloc(), tpcall(), tpconnect(), tpdiscon(), tpgetrply(), tprecv(), tpsend()
서버에서 서비스 요청을 또 다른 서비스 루틴으로 전달하는 함수로 자신의 서비스 처리를 종료하고 클라이언트의 요청을 svc 서비스 루틴으로 전달한다.
tpforward()는 서비스 루틴에서 마지막으로 호출되는 것으로 tpreturn()처럼 작동한다. tpreturn()과 마찬가지로 tpforward()가 Tmax 시스템으로 정상적으로 반환되기 위해서 tpforward()는 Tmax 시스템이 제어하는 서비스 루틴 내에서 호출되어야 한다.
data가 가리키는 데이터를 사용하여 svc로 지정된 서비스에게 요청을 전달한다. 요청을 전달하는 서비스 루틴은 어떤 응답도 수신하지 않는다. 요청이 전달된 후, 서비스 루틴은 Tmax 시스템에게로 반환한다. 그리고 서버는 자유롭게 다른 작업을 수행할 수 있다. tpforward()는 요청자로부터 아무 응답도 기대하지 않기 때문에 특별한 에러없이 어떤 서비스에게든지 전달될 수 있다.
서비스 루틴이 트랜잭션 모드에 있다면 그 트랜잭션은 트랜잭션 시작자(originator)가 tx_commit() 또는 tx_rollback() 중의 하나를 실행하여 트랜잭션을 완료할 때 비로소 완료될 수 있다. tpforward()는 tpreturn()과 마찬가지로 트랜잭션을 완료하지 않는다. 트랜잭션이 서비스 루틴 내에서 tx_begin()을 사용하여 시작된 것이라면 그 트랜잭션은 tpforward()의 호출 전에 tx_commit() 또는 tx_rollback() 둘 중의 하나로 먼저 완료되어야 한다. tpforward()로 연결된 모든 서비스들은 모두가 트랜잭션 모드이거나, 아니면 모두가 트랜잭션 모드가 아니어야 한다. 최종적으로 전달된 서버 프로세스가 tpreturn()을 이용하여 처음 서비스를 요청한 클라이언트에게 응답을 보낸다. tpforward()는 응답을 기다리고 있는 요청자에게 응답을 송신하는 책임을 다른 서버 프로세스에게 전가하는 것으로 멀티 노드 간에도 서비스가 이루어진다.
tpforward()는 서비스 루틴이 요청한 모든 서비스들에 대한 응답을 받은 후 호출되어야 한다. 수신되지 않은 응답에 대한 구별자들은 무효화되고 전달 요청은 전송되지 않는다. 대화형 서비스에서는 tpforward()가 호출될 수 없다.
다음은 tpforward 함수 흐름에 대한 그림이다.
프로토타입
# include <atmi.h> void tpforward (char *svc, char *data, long len, long flags)
파라미터
파라미터 | 설명 |
---|---|
svc | 버퍼를 받을 서비스명이다. |
data | NULL이 아니라면 tpalloc()에 의해 이전에 할당된 버퍼를 가리켜야 한다. 버퍼가 서비스 루틴에 송신된 것과 동일한 버퍼라면 Tmax 시스템이 이 버퍼에 대한 처리 책임을 갖는다. 서비스 루틴 작성자가 이 버퍼를 해제하려고 하면 이는 실패 처리된다. 그러나 tpforward()로 송신되는 버퍼가 서비스 호출할 때에 전달된 것과 동일한 버퍼가 아니라면 tpforward()가 그 버퍼를 해제한다. |
len | 송신될 데이터의 길이이다. data가 특별한 길이 명시가 필요없는 버퍼를 가리킨다면(예를 들어, STRUCT 타입 버퍼), len은 무시되고 0이 된다. data가 NULL이라면 len은 무시되고 데이터 길이가 0인 요청이 송신된다. 서비스 루틴 작성자는 tpforward() 호출 후 다시 제어권을 획득할 수 없기 때문에 TPSIGRSTRT가 암시적으로 정의된 형태의 블로킹 송신이 사용된다. tpforward() 수행 중에 시그널이 발생하여 수행이 중지되더라도 나중에 재수행되며, 블로킹 상황을 만나더라도 타임아웃 발생 전까지는 기다린 후 송신한다. |
flags | 현재 버전에서는 지원하지 않으나 TPNOFLAGS로 설정한다. |
반환값
서비스 루틴은 호출자인 Tmax 시스템에서 어떤 값도 반환하지 않는다. 서비스 루틴은 void로 선언된다.
오류
tpforward()가 정상적으로 수행되지 않을 경우 tperrno에 다음 값 중 하나가 설정된다.
에러 코드 | 설명 |
---|---|
[TPESVCERR] | 유효하지 않은 버퍼를 사용하는 경우, 유효한 tpacall(), tpconnect()의 반환값으로 cd를 반환하는 경우 , 대화형 통신에서 tpreturn() 대신 tpforward()를 사용한 경우, TPEV_DISCONIMM 이벤트가 발생한 경우, 트랜잭션 모드에서 XA operation이 실패한 경우(tx_begin(), tx_rollback(), tx_commit()) 경우에 발생한다. |
[TPETIME] | 서비스 루틴 작업 중이나 또는 요청을 전송하는 중에 트랜잭션 타임아웃이 발생한 경우에 TPETIME 에러가 반환된다. |
예제
#include <stdio.h> #include <usrinc/atmi.h> SWITCH(TPSVCINFO *msg) { int switch; char *buf; buf = (char *)tpalloc(“STRING”, NULL, 0); if (buf==NULL) { error processing } strcpy(buf, msg->data); data process… if (switch>5) tpforward(“SERVICE1”, buf, 0, 0); else tpforward(“SERVICE2”, buf, 0, 0); }
관련 함수
tpalloc(), tpconnect(), tpreturn()
개발자가 서비스를 수행하기 전에 Tmax 서버의 초기화 과정을 수행하는 작업을 처리하는 함수이다. Tmax 응용 서버 프로그램의 분리된 main의 초기화 과정에 tpsvrinit()을 호출한다. 이 루틴은 프로세스가 수행되고 난 후, 아직 어떤 서비스 요청도 처리하기 전에 호출된다. 그러므로 tpsvrinit() 루틴 내에 Tmax 통신이 수행되거나 트랜잭션이 정의될 수도 있다.
애플리케이션에서 tpsvrinit() 루틴을 제공하지 않는다면 Tmax가 제공하는 기본(default) 루틴이 대신 호출된다. 기본 tpsvrinit()은 트랜잭션을 처리하는 서버 그룹에 포함된 서버이면 tx_open()과 userlog()를 호출하여 서버가 성공적으로 시작되었음을 알린다.
애플리케이션별 명령어 라인 옵션(CLOPT)은 서버에게 전달되어 tpsvrinit()에서 처리될 수 있다. 명령어 라인 옵션(CLOPT)에 대한 자세한 설명은 source config 파일의 SERVER 절 중 CLOPT 항목을 참고한다. 옵션은 argc와 argv를 통해 전달된다.
getopt()가 Tmax 서버 main()에서 사용되기 때문에 optarg, optind, opterr가 tpsvrinit() 내에서 옵션 parsing 및 에러 검출을 제어하는 데 사용된다.
프로토타입
# include <tmaxapi.h> int tpsvrinit (int argc, char **argv)
파라미터
파라미터 | 설명 |
---|---|
argc | 명령 라인 파라미터의 개수이다. |
argv | 명령 라인 파라미터이다. |
반환값
반환값 | 설명 |
---|---|
0 | 함수 호출에 성공한 경우이다. |
음수 | 함수 호출에 실패한 경우이다. 어떤 서비스 요청도 받지 않고 서버 프로세스는 종료되고 에러는 발생하지 않는다. |
예제
#include <stdio.h> #include <usrinc/atmi.h> #include <usrinc/tmaxapi.h> EXEC SQL INCLUDE sqlca.h; tpsvrinit(int argc, char **argv) { EXEC SQL begin declare section; char user_name[30]; char user_passwd[30]; EXEC SQL end declare section; EXEC SQL CONNECT scott IDENTIFIED BY tiger; return(0); } SERVICE(TPSVCINFO *msg) { int ret, cd; char *buf; buf=tpalloc(“STRING”, NULL, 0); if (buf==NULL) { error processing } data process.... cd=tpgetclid(); if (cd==-1) { error processing } ret=tpsendtocli(cd, buf, 0, TPNOFLAGS); if (ret==-1) { error processing } data process.... printf(“ Sevice end\n”); EXEC SQL COMMIT WORK RELEASE; tpreturn(TPSUCCESS, buf, strlen(buf), 0); }
관련 함수
tx_open(), tpsvrdone()
UCS 방식 서버 프로세스를 종료하는 함수로, Tmax 응용 서버 프로그램의 분리된 main은 서비스 요청 처리를 모두 마치고 프로세스를 종료하기 전에 tpsvrdone()을 호출한다. 루틴이 실행될 때, 그 서버 프로세스는 여전히 시스템의 일부이기는 하지만 서비스는 지원하지 않는다. tpsvrdone() 루틴 내에서 Tmax 통신이 수행되거나 트랜잭션이 정의될 수도 있다.
tpsvrdone()이 대화형 연결을 유지하고 있는 경우는 Tmax는 대화형 연결을 종료한다. 비동기성 응답을 대기하고 있는 경우는 대기하고 있던 비동기성 응답들을 무시한다. 트랜잭션 모드에 있는 동안은 트랜잭션을 중지하고 서버는 바로 종료된다.
애플리케이션에서 tpsvrdone() 루틴을 제공하지 않는다면 Tmax가 제공하는 기본(default) 루틴이 대신 호출된다. 기본 tpsvrdone()은 트랜잭션을 처리하는 서버 그룹에 포함된 서버이면 tx_close()와 userlog()를 호출하여 서버가 곧 종료할 것임을 알린다. tpreturn()이나 tpforward() 중 하나가 tpsvrdone() 내에서 호출된다면 이러한 루틴들은 아무런 작동없이 단순히 반환만 한다.
프로토타입
# include <tmaxapi.h> int tpsvrdone(void)
반환값
tpsvrdone()은 개발자가 서버 프로세스의 종료를 수행하기 전에 필요한 작업을 수행하도록 작성하는 함수로 반환값은 없고 오류도 발생하지 않는다.
예제
#include <stdio.h> #include <usrinc/atmi.h> EXEC SQL INCLUDE sqlca.h; SERVICE(TPSVCINFO *msg) { int ret, cd; char *buf; EXEC SQL begin declare section; …. EXEC SQL end declare section; EXEC SQL CONNECT : scott IDENTIFIED BY : tiger; buf=tpalloc(“STRING”, NULL, 0); if (buf==NULL) { error processing } data process…. cd=tpgetclid(); if (cd==-1) { error processing } ret=tpsendtocli(cd, buf, 0, TPNOFLAGS); if (ret==-1) { error processing } data process.... tpsvrdone(); } void tpsvrdone() { printf(“ Sevice end\n”); EXEC SQL COMMIT WORK RELEASE; }
관련 함수
tx_close(), tpsvrinit()
Multithread 및 Multicontext 서버에서만 제공되는 함수이다. Tmax 서버는 서버 프로세스가 시작할 때 초기화 과정을 수행할 수 있는 tpsvrinit 함수를 제공한다. 마찬가지로 Multithread 및 Multicontext 서버에서는 tpsvrinit 함수가 호출된 이후에 Thread Pool에서 관리되는 서비스 스레드에 대해서도 스레드를 생성할 때 각각의 스레드마다 고유한 초기화 작업을 수행할 수 있도록 초기화 함수를 제공한다.
Thread Pool은 MINTHR, MAXTHR 항목에 따라 동작하므로 서버 프로세스가 처음 기동될 때에는 MINTHR 개수까지 서비스 스레드가 생성되면서 tpsvrthrinit()을 호출하게 되고, 이후 Thread Pool에 유휴 서비스 스레드가 없을 경우 최대 MAXTHR까지 필요한 개수만큼 서비스 스레드가 새롭게 생성되면서 이 함수를 호출하게 된다. 만약 MINTHR 항목이 0일 경우 프로세스 기동 초기에는 서비스 스레드를 생성하지 않기 때문에 tpsvrinit() 함수만 호출하고 서비스 요청이 들어오기를 기다린다.
tpsvrinit() 함수가 호출된 이후 그리고 각 스레드에서 서비스 요청을 처리하기 전에 수행되고 tpsvrinit() 함수에 전달된 것과 동일한 파라미터가 전달된다. 이 파라미터는 환경설정 SERVER 절의 CLOPT 항목에 설정한 내용들이다. 사용자는 tpsvrinit()과 tpsvrthrinit()으로 전달되는 파라미터가 동일하다는 것을 고려해서 작성해야 한다. 자세한 설명은 “10.1.3. tpsvrinit”을 참고한다.
프로토타입
# include <tmaxapi.h> int tpsvrthrinit (int argc, char **argv)
파라미터
파라미터 | 설명 |
---|---|
argc | 명령 라인 파라미터의 개수이다. |
argv | 명령 라인 파라미터이다. |
반환값
tpsvrthrinit() 함수를 통해 초기화 작업을 수행하는 과정에서 초기화가 실패할 경우 사용자는 -1을 리턴한다. 서버 프로세스는 tpsvrthrinit()을 호출한 후 -1이 리턴되면 프로세스 기동을 취소하고 종료된다.
반환값 | 설명 |
---|---|
0 | 함수 호출에 성공한 경우이다. |
음수 | 함수 호출에 실패한 경우이다. 서버 프로세스는 프로세스 기동을 취소하고 종료된다. |
예제
#include <stdio.h> #include <pthread.h> #include <usrinc/atmi.h> void tpsvrthrinit(int argc, char **argv) { param_t *param; param = get_threadspecificdata(); if (pthread_create(¶m->tid, NULL, THREAD_ROUTINE, (void *)param) != 0) { printf("user_create_thread failed\n"); return -1; } pthread_mutex_init(¶m->mutex, NULL); pthread_cond_init(¶m->cond, NULL); return 0; } void tpsvrthrdone() { void *ret; param_t *param; param = get_threadspecificdata(); param->state = EXIT; pthread_cond_signal(¶m->cond); pthread_join(param->tid, &ret); pthread_mutex_destroy(¶m->mutex); pthread_cond_destroy(¶m->cond); printf("user_create_thread destroyed\n"); } SERVICE(TPSVCINFO *msg) { param_t *param; param = get_threadspecificdata(); ... ret = tpgetctxt(¶m->ctxtid, TPNOFLAGS); ret = pthread_cond_signal(¶m->cond); ... } void *THREAD_ROUTINE(void *arg) { param_t *param; param = (param_t *)arg; while(1) { pthread_mutex_lock(¶m->mutex); { pthread_cond_wait(¶m->cond, ¶m->mutex); if (param->state == EXIT) break; if (tpsetctxt(param->ctxtid, TPNOFLAGS) == -1) { printf("tpsetctxt(%d) failed, [tperrno:%d]", param->ctxtid, tperrno); return NULL; } tpcall("MTOUPPER", sndbuf, 0, &rcvbuf, &rcvlen, TPNOFLAGS); ... if (tpsetctxt(TPNULLCONTEXT, TPNOFLAGS) == -1) { printf("tpsetctxt(TPNULLCONTEXT) failed, [tperrno:%d]", tperrno); return NULL; } ... } pthread_mutex_unlock(¶m->mutex); } return NULL; }
관련 함수
tpsvrthrdone()
Multithread 및 Multicontext 서버에서만 제공되는 함수이다. Multithread 및 Multicontext 서버는 서버 프로세스가 종료될 경우 tpsvrdone 함수를 수행하기에 앞서 서비스 스레드들을 종료시킨다. 서비스 스레드는 자신이 종료할 때 이 함수가 정의되어 있다면 자동으로 호출해준다. 개발자는 스레드가 종료되기 전에 처리해야 할 필요한 작업을 수행하도록 루틴을 작성하면 된다. 이 함수 안에서 Tmax 통신이 수행되거나 트랜잭션이 수행될 수 있다. 만약 이러한 작업들이 모두 완료되지 않은 상태에서 그냥 반환하게 되면 스레드가 종료되면서 미완료된 작업들은 모두 무시하게 된다.
함수를 사용하여 하나의 클라이언트가 기존에 생성된 다른 context를 현재 클라이언트에 할당할 수 있다. 대부분의 ATMI 함수들은 per-context 기반으로 되어 있다. 클라이언트는 여러 개의 context를 사용할 수 있지만 해당하는 순간에는 단 하나의 context만을 갖게 된다. 예를 들면 context1에서 tpacall()을 한 경우 다른 context를 사용했다 하더라도 tpgetrply()를 정상적으로 하기 위해서는 tpgetrply()를 하는 시점에서는 context1을 현재 context로 설정해 주어야 한다. 자세한 내용은 “10.1.4. tpsvrdone”을 참고한다.
프로토타입
# include <tmaxapi.h> int tpsvrthrdone(void)
반환값
tpsvrthrdone()은 개발자가 서버 프로세스의 종료를 수행하기 전에 필요한 작업을 수행하도록 작성하는 함수로 반환값은 없고 오류도 발생하지 않는다.
예제
tpsvrthrinit() 함수의 예제를 참고한다.
관련 함수
tpsvrthrinit()
함수를 호출하는 스레드에 현재 설정되어 있는 컨텍스트의 ID를 첫 번째 파라미터로 반환하는 함수이다. 클라이언트와 서버 프로그램에서 작성 방법에 차이가 있다. 자세한 내용은 “9.14.1. tpgetctxt”에서 이미 설명하였으므로 해당 부분을 참고한다.
현재 컨텍스트를 설정하는 함수이다. 클라이언트와 서버 프로그램에서 작성 방법에 차이가 있다. 자세한 내용은 “9.14.2. tpsetctxt”에서 이미 설명하였으므로 해당 부분을 참고한다.
서버에서 사용되는 함수로 지정된 클라이언트에게 비요청 메시지를 송신한다. tpbroadcast()는 Tmax 시스템에 접속되어 있는 임의의 클라이언트에 비요청 메시지를 전송한다. tpsendtocli()는 서버 프로세스에서 해당 서버 프로세스가 제공하는 서비스를 요청한 클라이언트에게만 비요청 메시지를 보내기 위해 사용한다.
프로토타입
# include <tmaxapi.h> int tpsendtocli (int clid, char *data, long len, long flags)
파라미터
파라미터 | 설명 |
---|---|
clid | tpgetclid()로 얻은 클라이언트의 유일한 번호이다. |
data | tpalloc()에 의해 할당된 버퍼로 data가 길이를 명시하지 않아도 되는 버퍼로 설정된 경우 len은 무시되고 보통 0이 사용된다. data가 길이를 반드시 명시해야 하는 버퍼로 설정된 경우 len은 0이 될 수 없다. data가 NULL인 경우 len은 무시된다. |
len | 송신하는 버퍼의 길이이다. |
flags | TPNOFLAG, TPUDP, TPFLOWCONTROL이 있으며 해당 flags에 따라 동작 방식이 결정된다. |
flags로 사용 가능한 값은 다음과 같다.
설정값 | 설명 |
---|---|
TPNOFLAG(0) | 메시지는 클라이언트에게 수신되어야 한다. 하지만 클라이언트가 수신된 메시지를 빠르게 처리하지 못한다면 요청한 결과를 수신할 때 오랜 시간이 걸릴 수 있다. |
TPUDP | TPUDP flags는 클라이언트와 데이터를 통신하는 방식이 UDP라는 의미가 아니다. 호출자가 데이터를 송신할 때, 송신할 내부 버퍼에 전달될 메시지가 가득 차서 보내지 못할 경우가 있다. 이 경우 데이터는 버려도 된다는 의미이다. 통신의 UDP처럼 데이터가 도중에 분실될 수 있다는 것을 의미이다. |
TPFLOWCONTROL | 클라이언트의 상태를 점검하고 다른 메시지를 요청할 수 있는지 확인한다. 해당 클라이언트로의 송신 메시지가 너무 많이 쌓여 있다면 tpsendtocli()는 –1을 반환하고 tperrno를 TPEQFULL로 설정한다. 이 flags는 Tmax 시스템의 부하를 줄여준다. |
반환값
반환값 | 설명 |
---|---|
1 | 함수 호출에 성공한 경우이다. |
-1 | 함수 호출에 실패한 경우이다. tperrno에 에러 코드가 설정된다. |
오류
tpsendcli()가 정상적으로 수행되지 않을 경우 tperrno에 다음 값 중 하나가 설정된다.
에러 코드 | 설명 |
---|---|
[TPEBADDESC] | clid가 유효하지 않다. |
[TPEPROTO] | tpsendtocli()가 부적절한 상황에서 호출되었다. |
[TPESYSTEM] | Tmax 시스템 에러가 발생한 경우로 자세한 정보는 로그 파일에 기록된다. |
[TPEOS] | 운영 시스템에 에러가 발생하였다. |
[TPEQFULL] | 송신할 메시지가 있으므로 같은 메시지일 경우에는 재전송할 필요가 없다. |
예제
#include <stdio.h> #include <usrinc/atmi.h> #include <usrinc/tmaxapi.h> SERVICE(TPSVCINFO *msg) { int ret, clid; char *buf; buf = (char *)tpalloc(“STRING”, NULL, 0); if (buf==NULL) { error processing } strcpy(buf, msg->data); data process…. clid = tpgetclid(); if (clid==-1) { error processing } ret=tpsendtocli(clid, (char *)buf, 0, 0); if (ret==-1) { error processing } tpreturn(TPSUCCESS, 0, 0, 0); }
관련 함수
tpbroadcast()
Tmax 시스템에 접속된 클라이언트의 번호를 알 수 있는 함수이다. 클라이언트 번호는 도메인 시스템 내에서 유일한 번호이다. 여러 멀티 노드로 도메인 시스템이 구축되어 있어도 유일한 번호를 클라이언트에게 부여한다. 이 함수는 서버에서만 사용할 수 있는 함수로, 일반적으로 서비스를 요청한 해당 클라이언트 ID를 구해서 tpsendtocli()에서 클라이언트로 메시지를 보내기 위해서 사용한다.
프로토타입
#include <tmaxapi.h> int tpgetclid(void)
반환값
반환값 | 설명 |
---|---|
0 이상의 정수값 | 함수 호출에 성공하는 경우이다. 클라이언트의 번호에 해당하는 0 이상의 정수값을 반환한다. |
-1 | 함수 호출에 실패한 경우이다. tperrno에 에러 코드가 설정된다. |
오류
tpgetclid()가 정상적으로 수행되지 않을 경우 tperrno에 다음 값 중 하나가 설정된다.
에러 코드 | 설명 |
---|---|
[TPESYSTEM] | tpgetclid()가 부적절한 상황에서 호출되었다. 예를 들어 클라이언트 프로그램 내에 사용된 경우 발생한다. |
[TPEOS] | 운영 시스템에 에러가 발생하였다. |
예제
#include <stdio.h> #include <usrinc/atmi.h> #include <usrinc/tmaxapi.h> SERVICE(TPSVCINFO *msg) { int ret, clid; char *buf; buf = (char *)tpalloc(“STRING”, NULL, 0); if (buf==NULL) { error processing } strcpy(buf, msg->data); data process… clid = tpgetclid(); if (clid==-1) { error process } ret=tpsendtocli(clid, buf, strlen(buf), 0); if (ret==-1) { error processing } data process…. tpreturn(TPSUCCESS,0,buf, strlen(buf), 0); }
관련 함수
tpsendtocli()
ID에 해당하는 클라이언트가 해당 서버 프로세스가 위치한 노드에 접속한 상태인지를 확인하는 함수이다. 주로 RDP 방식의 서버 프로그램을 개발할 때 서비스 루틴에서 접속한 클라이언트 ID를 저장하고 usermain() 루틴에서 tpsendtocli()로 메시지를 보내는 경우에 사용하면 불필요한 에러를 사전에 방지할 수 있다.
RDP 방식에서는 서버 프로세스가 위치한 노드에 직접 연결된 상태가 아니면 tpsendtocli()를 사용할 수 없다.
프로토타입
#include <tmaxapi.h> int tpchkclid(int clid)
파라미터
파라미터 | 설명 |
---|---|
clid | 클라이언트 번호로 tpgetclid()를 사용해서 얻어내는 값이다. |
반환값
반환값 | 설명 |
---|---|
-2 | 해당 클라이언트가 로컬 노드에 접속된 클라이언트가 아닌 경우이다. |
-1 | 해당 클라이언트가 접속되어 있지 않은 경우이다. |
1 | 해당 클라이언트가 정상적으로 접속된 경우이다. |
오류
tpchkclid()가 정상적으로 수행되지 않을 경우 tperrno에 다음 값 중 하나가 설정된다.
에러 코드 | 설명 |
---|---|
[TPEINVAL] | 클라이언트가 로컬 노드에 접속되어 있지 않은 경우이거나 입력된 클라이언트 번호가 잘못된 값이다. |
[TPENOREADY] | 클라이언트가 정상적으로 접속되어 있지 않은 상태이다. |
예제
int _discon(char **buf) { int clid, n; clid = tpgetclid(); n = tpchkclid(clid); if (n < 0) { printf(“Invalid Client\n”); return -1; } ... }
관련 함수
tpgetclid()
UCS 방식의 서버 프로그램에서 사용하는 함수에 대해 설명한다.
스케줄링 관련 API
UCS 방식은 사용자가 개발한 usermain() 루틴이 main() 루틴처럼 사용되므로 스케줄링 API를 통하여 TMM과 CLH로부터 오는 여러 가지 메시지를 처리해야 한다.
함수 | 기 능 |
---|---|
tpschedule | 지정시간(초) 동안 CLH 혹은 사용자 설정 FD에 메시지가 도착했는지 확인한다. |
tpuschedule | 지정시간(마이크로초) 동안 CLH 혹은 사용자 설정 FD에 메시지가 도착했는지 확인한다. |
소켓 FD 관련 매크로
소켓 관련 매크로는 앞서 설명한 tpschedule()등의 UCS 스케줄러에 사용자의 소켓 FD를 같이 사용하기 위한 것으로 일반 네트워크 프로그램에서 사용하는 FD_SET, FD_CLR, FD_ISSET과 유사하다.
서비스 포워딩
시스템이 아닌 일반 호스트 시스템과 연동하여 운영하는 경우 일반적으로 서버 프로그램에서 소켓을 열고 데이터를 주고받는 과정을 클라이언트를 대신하여 수행한다. 그러나 외부 호스트 시스템과의 연결이 불안정하거나 서비스 시간이 길 경우 해당 서버 프로그램은 block 상태에 놓이게 되고 추가적인 서비스를 수행하지 못한다.
이러한 경우를 해결하기 위해 서비스 루틴은 클라이언트의 요청을 받아 클라이언트의 정보를 저장하고 외부 호스트로 요청을 보내는 부분까지만 담당한다. 응답은 usermain() 루틴을 이용하여 저장된 클라이언트의 정보와 함께 다른 서비스 루틴으로 넘겨진다. 그 서비스 루틴이 클라이언트에게 결과값을 보내도록 하면 서버 프로그램은 block되지 않고도 모든 과정을 수행할 수 있게 된다.
함수 | 기 능 |
---|---|
tpsavectx | 서버 라이브러리 내에 클라이언트의 정보를 저장한다. |
tpgetctx | 서버 라이브러리 내의 CTX_T 구조체의 값을 사용자 변수에 저장한다. |
tpcancelctx | 서버 라이브러리 내의 CTX_T 구조체의 내용을 삭제한다. |
tprelay | tpgetctx() 혹은 tpsavectx()로 얻은 클라이언트 정보/트랜잭션 정보와 함께 다른 서비스 루틴으로 클라이언트의 관리를 전달한다(TCS 방식 서버 프로그램에서 사용되는 tpforward()와 유사하다). |
usermain() 루틴 내에서의 비동기형 통신
usermain() 루틴 내에서 서비스 시간이 긴 비동기형 통신을 사용하는 경우 tpgetreply()에서 block이 발생하여 스케줄링이 늦어지는 경우가 있다. 서비스 결과를 tpgetreply()로 받지 않고 Callback 함수을 지정하면 스케줄링에 지장 없이 결과값을 처리할 수 있다. 그러나 루프 시간이 짧은 usermain() 내에서 매번 비동기형 통신이 발생하는 경우 최대 비동기형 서비스 수를 초과하게 되어 에러가 발생하게 되므로 주의한다.
각 함수의 관련 함수에 대한 자세한 내용은 "Tmax Reference Guide"를 참고한다.
UCS 형태의 서버 프로세스에서만 사용 가능한 함수로 UCS 서버 프로세스에서 데이터의 도착을 기다린다. 최대 타임아웃 시간동안 sleep하다가 그 안에 데이터가 도착하면 즉시 반환한다.
tpschedule() 함수는 데이터가 도착했을 때 해당되는 서비스가 자동적으로 수행되고 난 후에 반환된다. 그러므로 데이터가 도착한 후에 사용자가 임의로 서비스를 수행하면 안 된다.
서비스는 무조건 시스템에 의해서 항상 수행되므로 UCS 형태의 서비스 프로그램이라도 이점을 주의해야 한다.
프로토타입
#include <ucs.h> int tpschedule(int timeout)
파라미터
파라미터 | 설명 |
---|---|
timeout | 기다리고자 하는 시간을 초 단위로 입력해야 한다.
|
반환값
반환값 | 설명 |
---|---|
양의 정수 | 함수가 수행에 성공해서 데이터가 도착한 경우이다. |
-1 | 타임아웃 시간까지 데이터가 도착하지 않은 경우 또는 함수가 수행에 실패해서 에러가 발생한 경우이다. 타임아웃 시간까지 데이터가 도착하지 않으면 -1을 반환하고, tperrno에13번(TPETIME)이 설정된다. 그 외의 경우 tperrno에 에러 코드가 설정된다. |
오류
tpschedule()가 정상적으로 수행되지 않을 경우 tperrno에 다음 값 중 하나가 설정된다.
에러 코드 | 설명 |
---|---|
[TPESYSTEM] | Tmax 시스템 에러가 발생한 경우로 자세한 정보는 로그 파일에 기록된다. |
[TPEOS] | 운영 시스템에 에러가 발생하였다. |
[TPETIME] | 타임아웃 시간까지 데이터가 도착하지 않았다. |
[TPEPROTO] | 함수가 부적절한 상황에서 호출되었을 경우이다. 예를 들어, 서비스 내에서 호출하는 경우 발생한다. |
예제
#include <stdio.h> #include <usrinc/atmi.h> #include <usrinc/ucs.h> int usermain(int argc, char *argv[]) { ... while(1) { ... tpschedule(3); ret = tpcall(“SERVICE”, (char *)buf, strlen(buf), (char **)&buf, (long *)&rlen, TPNOFLAGS); if (ret == -1) { error processing} ... } }
관련 함수
tpsleep(), tp_sleep(), tp_usleep()
UCS 서버 프로세스에서 데이터의 도착을 microsecond 단위로 입력한 시간동안 기다리는 함수이다. tpuschedule()은 UCS 형태의 서버 프로세스에서만 사용 가능한 함수로, 최대 타임아웃(timeout) 시간동안 대기하다가 정해진 시간 안에 데이터가 도착하면 즉시 반환한다.
프로토타입
#include <ucs.h> int tpuschedule (int timeout)
파라미터
파라미터 | 설명 |
---|---|
timeout | 대기할 시간을 시간을 microsecond 단위로 입력해야 한다.
|
반환값
반환값 | 설명 |
---|---|
0 | 타임아웃 시간까지 데이터가 도착하지 않는 경우이다. |
양의 정수 | 타임아웃 시간까지 데이터가 도착한 경우이다. |
-1 | 함수 호출에 실패한 경우이다. tperrno에 에러 코드가 설정된다. |
오류
tpuschedule()가 정상적으로 수행되지 않을 경우 tperrno에 다음 값 중 하나가 설정된다.
에러 코드 | 설명 |
---|---|
[TPESYSTEM] | Tmax 시스템 에러가 발생한 경우로 자세한 정보는 로그 파일에 기록된다. |
[TPEOS] | 운영 시스템에 에러가 발생하였다. |
예제
... #include <stdio.h> #include <usrinc/atmi.h> #include <usrinc/ucs.h> int usermain(int argc, char *argv[]) { ... while(1) { ... tpuschedule(3000000); ret = tpcall(“SERVICE”, (char *)buf, strlen(buf), (char **)&buf, (long *)&rlen, TPNOFLAGS); if (ret == -1) { error processing } ... } }
관련 함수
tpschedule()
소켓 fd를 UCS 프로세스의 외부 소켓 스케줄러에 등록하는 함수로 UCS 방식 프로세스를 사용한 소켓 fd를 켤 때 사용된다. UCS 스케줄러는 TMM, CLH 뿐만 아니라 해당 소켓 fd에 도착한 메시지도 같이 검사한다. 사용자가 지정한 소켓에 메시지가 도착했을 경우 tpschedule()은 별도의 처리없이 정상 결과(UCS_USER_MSG)를 반환하며 어떤 소켓에 메시지가 도착했는지를 알기 위해서는 아래에 설명된 tpisetfd()를 사용해야 한다.
프로토타입
#include <ucs.h> int tpsetfd (int fd)
파라미터
파라미터 | 설명 |
---|---|
fd | 등록할 소켓 fd를 설정한다. |
반환값
반환값 | 설명 |
---|---|
1 | 함수 호출에 성공한 경우이다. |
-1 | 함수 호출에 실패한 경우이다. tperrno에 에러 코드가 설정된다. |
오류
tpsetfd()가 정상적으로 수행되지 않을 경우 tperrno에 다음 값 중 하나가 설정된다.
에러 코드 | 설명 |
---|---|
[TPESYSTEM] | Tmax 시스템 에러가 발생한 경우로 자세한 정보는 로그 파일에 기록된다. |
[TPEOS] | 운영 시스템에 에러가 발생하였다. |
예제
#include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <errno.h> #include <usrinc/ucs.h> ... #define SERV_ADDR “168.126.185.129” #define SERV_PORT 1500 int fd_read(int, char *, int); extern int errno; int usermain(int argc, char *argv[]) { ... int listen_fd, n, newfd; struct sockaddr_in my_addr, child_addr; socklen_t child_len; buf = tpalloc(“STRING”, NULL, 0); if (buf == NULL){ error processing } memset((void *)&my_addr, NULL, sizeof(my_addr)); memset((void *)&child_addr, NULL, sizeof(child_addr)); listen_fd = socket(AF_INET, SOCK_STREAM, 0); if (listen_fd == -1){ error processing } my_addr.sin_family = AF_INET; inaddr = inet_addr(SERV_ADDR); my_addr.sin_port = htons((unsigned short)SERV_PORT); if (inaddr != -1){ memcpy((char *)&my_addr.sin_addr, (char *)&inaddr, sizeof(inaddr)); } ret = bind(listen_fd, (struct sockaddr *)&my_addr, sizeof(my_addr)); if (ret == -1){ error processing } ret = listen(listen_fd, 5); if (ret == -1){ error processing } ret = tpsetfd(listen_fd); if (ret == -1){ error processing } ... while(1) { n = tpschedule(10); ... if (n == UCS_USER_MSG){ if (tpissetfd(listen_fd)) { child_len = sizeof(child_addr); newfd = accept(listen_fd, &child_addr, &child_len); if (newfd == -1){ error processing } ret = tpsetfd(newfd); if (ret == -1){ error processing } } if (tpissetfd(newfd)){ /* 소켓으로 부터 버퍼를 읽는다 */ fd_read(newfd, buf, 1024); ret = tpcall(“SERVICE”, (char *)buf, sizeof(buf), (char **)&buf, (long *)&rlen, TPNOFLAGS); if (ret == -1){ error processing } ... tpclrfd(newfd); close(newfd); } ... } return 1; }
관련 함수
tpclrfd(), tpissetfd()
서버에서 UCS 프로세스에서 소켓 fd로 데이터가 도착했는지를 검사하는 함수로, UCS 방식 서버 프로세스의 외부 소켓을 스케줄링하는 데 사용한다.
프로토타입
#include <ucs.h> int tpissetfd (int fd)
파라미터
파라미터 | 설명 |
---|---|
fd | 테스트할 fdset 내부의 fd를 설정한다. |
반환값
반환값 | 설명 |
---|---|
양수 | 메시지가 도착했을 경우이다. |
0 | 메시지가 도착하지 않은 경우이다. |
-1 | 함수 호출에 실패한 경우이다. tperrno에 에러 코드가 설정된다. |
오류
tpissetfd()가 정상적으로 수행되지 않을 경우 tperrno에 다음 값 중 하나가 설정된다.
에러 코드 | 설명 |
---|---|
[TPESYSTEM] | Tmax 시스템 에러가 발생하였다. 자세한 정보는 로그 파일에 기록된다. |
[TPEOS] | 운영 시스템에 에러가 발생하였다. |
예제
#include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <errno.h> #include <usrinc/ucs.h> ... #define SERV_ADDR “168.126.185.129” #define SERV_PORT 1500 int fd_read(int, char *, int); extern int errno; int usermain(int argc, char *argv[]) { ... int listen_fd, n, newfd; struct sockaddr_in my_addr, child_addr; socklen_t child_len; buf = tpalloc(“STRING”, NULL, 0); if (buf == NULL){ error processing } memset((void *)&my_addr, NULL, sizeof(my_addr)); memset((void *)&child_addr, NULL, sizeof(child_addr)); listen_fd = socket(AF_INET, SOCK_STREAM, 0); if (listen_fd == -1){ error processing } my_addr.sin_family = AF_INET; inaddr = inet_addr(SERV_ADDR); my_addr.sin_port = htons((unsigned short)SERV_PORT); if (inaddr != -1) memcpy((char *)&my_addr.sin_addr, (char *)&inaddr, sizeof(inaddr)); ret = bind(listen_fd, (struct sockaddr *)&my_addr, sizeof(my_addr)); if (ret == -1){ error processing } ret = listen(listen_fd, 5); if (ret == -1){ error processing } tpsetfd(listen_fd); ... while(1) { n = tpschedule(10); ... if (n == UCS_USER_MSG){ if (tpissetfd(listen_fd)) { child_len = sizeof(child_addr); newfd = accept(listen_fd, &child_addr, &child_len); if (newfd == -1){ error processing } tpsetfd(newfd); } if (tpissetfd(newfd)){ /* 소켓으로부터 버퍼를 읽는다 */ fd_read(newfd, buf, 1024); ret = tpcall(“SERVICE”, (char *)buf, sizeof(buf), (char **)&buf, (long *)&rlen, TPNOFLAGS); if (ret == -1){ error processing } ... tpclrfd(newfd); close(newfd); } ... } } return 1; }
관련함수
tpissetfd(), tpsetfd()
UCS 방식 프로세스 내부의 fdset의 소켓 fd를 off시키는 데 사용되는 함수로, UCS 방식 서버 프로세스의 외부 소켓을 스케줄링하는 경우에 사용한다.
프로토타입
#include <ucs.h> int tpclrfd (int fd)
파라미터
파라미터 | 설명 |
---|---|
fd | off할 내부 fdset의 소켓이다. |
반환값
반환값 | 설명 |
---|---|
1 | 함수 호출에 성공한 경우이다. |
-1 | 함수 호출에 실패한 경우이다. tperrno에 에러 코드가 설정된다. |
오류
tpclrfd()가 정상적으로 수행되지 않을 경우 tperrno에 다음 값 중 하나가 설정된다.
에러 코드 | 설명 |
---|---|
[TPESYSTEM] | Tmax 시스템 에러가 발생한 경우로 자세한 정보는 로그 파일에 기록된다. |
[TPEOS] | 운영 시스템에 에러가 발생하였다. |
예제
#include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <errno.h> #include <usrinc/ucs.h> …. #define SERV_ADDR “168.126.185.129” #define SERV_PORT 1500 int fd_read(int, char *, int); extern int errno; int usermain(int argc, char *argv[]) { ... int listen_fd, n, newfd; struct sockaddr_in my_addr, child_addr; socklen_t child_len; buf = tpalloc(“STRING”, NULL, 0); if (buf == NULL){ error processing } memset((void *)&my_addr, NULL, sizeof(my_addr)); memset((void *)&child_addr, NULL, sizeof(child_addr)); listen_fd = socket(AF_INET, SOCK_STREAM, 0); if (listen_fd == -1){ error processing } my_addr.sin_family = AF_INET; inaddr = inet_addr(SERV_ADDR); my_addr.sin_port = htons((unsigned short)SERV_PORT); if (inaddr != -1){ memcpy((char *)&my_addr.sin_addr, (char *)&inaddr, sizeof(inaddr)); } ret = bind(listen_fd, (struct sockaddr *)&my_addr, sizeof(my_addr)); if (ret == -1){ error processing } ret = listen(listen_fd, 5); if (ret == -1){ error processing } tpsetfd(listen_fd); ... while(1) { n = tpschedule(10); ... if (n == UCS_USER_MSG){ if (tpissetfd(listen_fd)) { child_len = sizeof(child_addr); newfd = accept(listen_fd, &child_addr, &child_len); if (newfd == -1){ error processing } tpsetfd(newfd); } if (tpissetfd(newfd)){ /* 소켓으로 부터 버퍼를 읽는다 */ fd_read(newfd, buf, 1024); ret = tpcall(“SERVICE”, (char *)buf, sizeof(buf), (char **)&buf, (long *)&rlen, TPNOFLAGS); if (ret == -1){ error processing } ... ret = tpclrfd(newfd); if (ret == -1){ error processing } close(newfd); } ... } return 1; }
관련 함수
tpissetfd()
UCS 프로세스에서 사용되며 클라이언트의 정보를 내부적으로 관리하도록 한다. tpsavectx()는 tprelay() 함수와 함께 사용된다. tprelay()는 처리 결과를 다른 서비스로 전달하는 역할을 수행한다. 일반적인 서비스 프로그램에서 tpforward 형식으로 다른 서비스를 부른 것과 동일하게 동작한다. 결과적으로 호출된 서비스에서는 처리된 결과값을 해당 클라이언트에게 전달한다.
tpsavectx() 함수는 대외기관 업무와 같이 다른 프로토콜이 이용되며 시간이 많이 소요되어 채널이 묶일 수 있는 가능성이 많은 경우에 사용된다.
일반적으로 사용되는 형태는 다음과 같다.
클라이언트 → svc1 → svc2(service, tpsavectx) → 대외기관 클라이언트 ← svc3 ← svc2(usermain, tprelay) ← 대외기관
클라이언트가 svc1에게 원하는 서비스를 요청한다.
svc1에서는 tpforward(...TPNOREPLY)를 이용해서 svc2를 호출한다.
svc2는 UCS 프로세스에 존재하는 서비스이며 서비스 루틴 내에서 tpsavectx()를 사용하여 클라이언트의 정보를 저장하며 대외기관과 통신한다.
결과는 usermain에서 수신하며 이를 tprelay()를 통해서 svc3에게 전달한다. svc3는 svc2에서 tpforward로 자신을 호출한 것으로 간주하여 최종 결과를 주어진 클라이언트에게 전달한다.
svc1에서 서비스를 TPNOREPLY로 전달하고 있기 때문에 채널이 묶이는 것을 방지할 수 있어 작은 수의 업무 프로세스로도 많은 클라이언트를 감당할 수 있다. 또한 하나의 UCS 프로세스로서 송, 수신 프로세스 역할을 겸함으로써 비교적 단순한 시스템을 구성할 수 있다. 이는 시스템 관리 측면에서도 효율적이다.
프로토타입
#include <ucs.h> CTX_T * tpsavectx(void)
반환값
반환값 | 설명 |
---|---|
CTX_T | 함수 호출에 성공한 경우이다. |
NULL | 함수 호출에 실패한 경우이다. tperrno에 에러 코드가 설정된다. |
오류
tpsavectx()가 정상적으로 수행되지 않을 경우 tperrno에 다음 값 중 하나가 설정된다.
에러 코드 | 설명 |
---|---|
[TPEPROTO] | tpsavectx() 함수는 반드시 서비스 루틴 내에서 사용해야 한다. 서비스 루틴이 아닌 곳에 사용되는 경우에는 TPEPROTO 에러가 발생한다. tpsvrinit() 혹은 tpsvrdone()에서는 사용될 수 없다. |
[TPESYSTEM] | 메모리 할당 오류가 발생하였다. |
예제
... #include <stdio.h> #include <usrinc/ucs.h> CTX_T *ctx = NULL; usermain(int argc, char *argv[]) { int ret, i; char *rcvbuf, *sndbuf; long sndlen; rcvbuf = (char *)tpalloc(“CARRAY”,NULL, 1024); if (rcvbuf == NULL){ error processing } i = 0; while(1) { tpschedule(1); if (ctx != NULL) { i++; if ((sndbuf = (char *)tpalloc(“CARRAY”,NULL, 1024)) == NULL) { error processing } else { ... ret = tprelay(“TPRETURN”, sndbuf, sndlen, 0, ctx); if (ret==-1) { error processing } data process... ctx = NULL; tpfree(sndbuf); } } } } int RELAY(TPSVCINFO *rqst) { ... ctx = tpsavectx(); tpreturn(TPSUCCESS, 0, rqst->data, rqst->len, 0); }
관련 함수
tpreturn(), tpforward(), tprelay()
현재 클라이언트의 정보를 사용자가 선언, 할당한 CTX_T 구조체에 복사해오는 함수이다. tpgetctx()를 사용했을 경우 tprelay()로 이 정보를 사용하지 않을 경우 해당 서비스 루틴이 완료되더라도 클라이언트는 계속 응답을 기다리게 된다.
tpgetctx()로 얻어진 정보는 tpcancelctx()로 취소할 수 없으므로 반드시 tprelay()를 사용해야 하고 서비스 루틴 내에서만 사용할 수 있다.
프로토타입
#include <tmaxapi.h> int tpgetctx (CTX_T *ctxp)
파라미터
파라미터 | 설명 |
---|---|
ctxp | tpsavectx()로 저장된 클라이언트의 정보를 CTX_T 구조체로 받아온다. |
예제
RELAY_SVC(TPSVCINFO *msg) { CTX_T *ctxp; ctxp=(CTX_T *)malloc(sizeof(CTX_T); .... ret = tpgetctx(ctxp); if (ret<0) { error process routine } ..... }
tpsavectx()로 저장된 클라이언트 정보들 중 해당 구조체의 내용을 취소하는 함수이다. tprelay()를 수행하지 않아도 서비스 루틴이 종료되면 정상적으로 결과가 반환된다.
tpgetctx()는 서비스 루틴 내에서만 사용할 수 있다.
프로토타입
#include <ucs.h> int tpcancelctx(CTX_T *ctxp);
파라미터
파라미터 | 설명 |
---|---|
ctxp | 라이브러리 내부에 저장된 CTX_T 구조체의 내용을 삭제한다. |
다음은 CTX_T 구조체의 정의이다.
typedef struct { int version[4]; char data[CTX_USR_SIZE - 16]; } CTX_T;
예제
RELAY_SVC(TPSVCINFO *msg) { ..... ctxp = (CTX_T *)tpsavectx(); ..... ret=tpcancelctx(ctxp); if (ret<0) { error process routine } ..... tpreturn(TPFAIL, sqlca.sqlcode, NULL, 0, TPNOFLAGS); }
UCS 형태의 서버 프로세스에서만 사용 가능한 함수로, 서비스를 요청한 클라이언트에 대한 정보를 담아서 또 다른 서비스를 요청하는 방식으로 멀티 노드 간에도 서비스가 이루어진다. 이런 형식을 취하면 tprelay()를 통해서 호출된 서비스는 마치 클라이언트가 자기를 직접 호출한 것으로 인식하고 서비스의 수행 결과는 최초 서비스를 요청한 클라이언트에게 전달된다.
서비스 수행 결과를 호출한 클라이언트에게 전달할 수 있으므로 UCS 프로세스에서 간단한 구성을 통해 빠른 응답을 유도할 수 있다. 대체적으로 2~3번의 서비스를 호출해야만 결과를 얻어낼 수 있는 프로그램 루틴인 대외기간 업무와 연동하여 서비스를 처리하는 경우에 사용하는 것이 좋다.
만약 tpsavcctx() 또는 tpgetctx()를 통해 클라이언트 정보를 저장한 이후에 tprelay()를 통해 다른 서비스를 요청하지 않은 상태에서 서버 프로세스가 종료되는 경우에는 자동으로 서비스 호출자에게 에러 응답이 전달된다. 에러 응답의 전달과 관련해서는 환경설정 SERVER 절의 CTX_EREPLY 옵션을 참고한다. 이러한 동작은 Tmax v5.0 SP2 이후 버전에서부터 지원되며, 이전 버전에서는 이와 같은 상황에서 서비스 호출자에게 에러 응답이 전달되지 않았다.
프로토타입
#include <ucs.h> int tprelay(char *svc, char *data, long len, long flags, CTX_T *ctxp);
파라미터
파라미터 | 설명 |
---|---|
svc | Tmax 환경 파일에 등록된 서비스명을 지정한다. |
data | 서비스를 호출할 때 전달되는 데이터로 NULL이 아닌 경우는 반드시 tpalloc()으로 할당된 버퍼를 사용해야 한다. |
len | 보내는 데이터의 길이를 지정한다. CARRAY, X_OCTET, 구조체 배열 타입일 경우에는 반드시 설정해야 한다. |
flags | 현재 지원하지 않는 파라미터로 TPNOFLAGS를 설정한다. |
ctxp | tpgetctx() 혹은 tpsavectx()로 받아온 정보 구조체이다. |
반환값
반환값 | 설명 |
---|---|
1 | 함수 호출에 성공한 경우이다. |
-1 | 함수 호출에 실패한 경우이다. tperrno에 에러 코드가 설정된다. |
오류
tprelay()가 정상적으로 수행되지 않을 경우 tperrno에 다음 값 중 하나가 설정된다.
에러 코드 | 설명 |
---|---|
[TPEINVAL] | 파라미터가 유효하지 않다. 예를 들어 ctxp가 NULL이거나 잘못된 버퍼를 사용한 경우에 발생한다. |
[TPESYSTEM] | Tmax 시스템적인 에러가 발생하였다. |
예제
... #include <stdio.h> #include <usrinc/ucs.h> CTX_T *ctx = NULL; DUMMY(TPSVCINFO *msg) { data process …. } usermain(int argc, char *argv[]) { int ret, i; char *rcvbuf, *sndbuf; long sndlen; rcvbuf = (char *)tpalloc(“CARRAY”,NULL, 1024); if (rcvbuf == NULL){ error processing } i = 0; while(1) { tpschedule(1); if (ctx != NULL) { i++; if ((sndbuf = (char *)tpalloc(“CARRAY”,NULL, 1024)) == NULL) { error processing } else { ... ret = tprelay(“TPRETURN”, sndbuf, sndlen, 0, ctx); if (ret==-1) { error processing } data process... ctx = NULL; tpfree(sndbuf); } } } } int RELAY(TPSVCINFO *rqst) { ... ctx = tpsavectx(); tpreturn(TPSUCCESS, 0, rqst->data, rqst->len, 0); }
관련 함수
tpreturn(), tpforward()
서버에서 UCS의 비동기형 요청에 대한 응답을 받는 루틴을 설정하는 함수로, UCS 방식 프로세스가 서버 프로그램으로부터 응답을 받았을 때 이를 처리할 루틴을 설정한다. UCS 방식 서버 프로세스에 tpgetreply() 대신 사용된다.
프로토타입
# include <ucs.h> int tpregcb (UcsCallback)
파라미터
파라미터 | 설명 |
---|---|
UcsCallback | UCS에서 비동기형 요청에 대한 응답을 처리하는 Callback 함수를 지정한다. |
반환값
반환값 | 설명 |
---|---|
1 | 함수 호출에 성공한 경우이다. |
-1 | 함수 호출에 실패한 경우이다. tperrno에 에러 코드가 설정된다. |
오류
tpregcb()가 정상적으로 수행되지 않을 경우 tperrno에 다음 값 중 하나가 설정된다.
에러 코드 | 설명 |
---|---|
[TPESYSTEM] | Tmax 시스템 에러가 발생하였다. 자세한 정보는 로그 파일에 기록된다. |
[TPEOS] | 운영 시스템에 에러가 발생하였다. |
예제
... #include <stdio.h> #include <usrinc/atmi.h> #include <usrinc/ucs.h> void reply_receive(UCSMSGINFO *reply); DUMMY(TPSVCINFO *msg) { data process …. } int usermain(int argc, char *argv[]) { int ret; char *buf ret = tpregcb(reply_receive); if (ret == -1){ error processing } buf=tpalloc(“STRING”, NULL, 0); if (buf==NULL) { error processing } data process… while(1) { ... tpschedule(3); cd = tpacall(“SERVICE”, buf, strlen(buf), TPNOFLAGS); if (cd < 0) { error processing } ... } } void reply_receive(UCSMSGINFO *reply) { printf(“data....%s\n”, reply->data); }
관련 함수
tpunregcb()
UCS 방식의 서버 프로세스에서 비동기형 요청에 대한 응답을 받는 루틴을 재설정하는 함수로, 서버 프로그램에서 응답을 받으면 수행되는 루틴을 재설정(reset)한다.
프로토타입
#include <ucs.h> int tpunregcb (void)
반환값
반환값 | 설명 |
---|---|
1 | 함수 호출에 성공한 경우이다. |
-1 | 함수 호출에 실패한 경우이다. tperrno에 에러 코드가 설정된다. |
오류
tpunregcb()가 정상적으로 수행되지 않을 경우 tperrno에 다음 값 중 하나가 설정된다.
에러 코드 | 설명 |
---|---|
[TPESYSTEM] | Tmax 시스템 에러가 발생한 경우로 자세한 정보는 로그 파일에 기록된다. |
[TPEOS] | 운영 시스템에 에러가 발생하였다. |
예제
... #include <usrinc/atmi.h> #include <usrinc/ucs.h> void reply_receive(UCSMSGINFO *reply); int usermain(int argc, char *argv[]) { ... ret = tpregcb(reply_receive); if (ret == -1){ error processing } ret = tpunregcb(); if (ret == -1){ error processing } while(1) { ... tpschedule(3); cd = tpacall(“SERVICE”, buf, strlen(buf), TPNOFLAGS); if (cd < 0) { error processing } ... } } void reply_receive(UCSMSGINFO *reply) { printf(“first reply receive\n”); printf(“data....%s\n”, reply->data); }
관련 함수
tpregcb()