RCAH 예제
본 장에서는 RCAH Customizing과 예제에 대해서 기술한다.
1. RCAH Customizing
각 사이트(Site)마다 통신 프로그램(Client)과 RCA 사이의 통신 프로토콜이 다르기 때문에 프로토콜을 맞추어야 한다. 따라서 RCAH 모듈에서 이 부분을 처리하는 int thrmain(RCAINFO info)을 개발자가 customizing 해야 한다. 이 함수는 스레드의 일부이기 때문에 작성할 때 MT-Safe를 만족하도록 작성해야 한다.
RCAH에 대하여 좀 더 자세히 보면 RCAH는 RCA_NTHR에 정의된 값만큼 스레드를 생성하고, 클라이언트로부터 요청이 있으면 Thread Pool에서 스레드 하나를 할당하여 기본적인 환경을 설정하고 클라이언트의 요청이 발생하는 시점에 사용자가 작성한 thrmain()을 호출하는 방식으로 처리된다. thrmain()의 수행이 종료되면 클라이언트와 연결은 끊어지며 스레드는 다시 Thread Pool에 반환된다.
전역 변수를 사용하여 Write할 경우는 RCAH가 멀티 스레드이기 때문에 Lock 처리를 반드시 해야 한다. tmaxreadenv()를 사용할 경우 메모리 손실이 발생하므로 사용할 수 없다. |
2. 예제
다음은 Solaris 2.7 32 Bit 머신에서 테스트한 예제이다. TMAXDIR 환경변수는 시스템에 설정되어 있는 것으로 가정한다.
2.1. Makefile
다음은 Makefile 예제이다.
TARGET = rcah LIBS = -lrcah -lpthread -lsocket CFLAGS = -I$(TMAXDIR) APOBJS = $(TARGET).o TMAX_INCDIR = $(TMAXDIR)/usrinc TMAX_BINDIR = $(TMAXDIR)/bin TMAX_LIBDIR = $(TMAXDIR)/lib OBJS = $(APOBJS) .c.o: $(CC) $(CFLAGS) -c $< $(TARGET): $(APOBJS) $(CC) $(CFLAGS) -L$(TMAX_LIBDIR) -o $(TARGET) $(OBJS) $(LIBS) $(USERLIBS) clean: -rm -f *.o core $(TARGET)
2.2. 프로그램
다음은 프로그램의 헤더 파일과 소스 파일 예제이다.
<rca.h>
/* ------------------------- usrinc/rca.h --------------------- */ /* */ /* Copyright (c) 2002 TmaxSoft Co., Ltd */ /* All Rights Reserved */ /* */ /* ------------------------------------------------------------ */ #ifndef _TMAX_RCA_H #define _TMAX_RCA_H #ifndef _TMAX_MTLIB #define _TMAX_MTLIB 1 #endif #include <usrinc/tmaxapi.h> #ifndef _WIN32 #define __cdecl #endif /* ------ type definition ------ */ typedef struct { int fd; int portno; int count; int status1; int status2; void *user_data; void *system_data; } *RCAINFO; #if defined (__cplusplus) extern "C" { #endif #ifndef _TMAX_KERNEL int thrmain(RCAINFO); int thrinit(RCAINFO); int thrdone(RCAINFO); #endif #if defined (__cplusplus) } #endif #endif
<rcah.c>
#include <stdlib.h> #include <string.h> #include <unistd.h> #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <netinet/in.h> #include <arpa/inet.h> #include <pthread.h> #include <errno.h> #include <usrinc/rca.h> struct msg { int len; char svcname[16]; }; int start_flag; int thrinit(RCAINFO info) { int n; n = tpstart(NULL); if (n < 0) { printf("RCA_%d: tpstart fail, tperrno = %d, errno = %d\n", pthread_self(), tperrno, errno); return -1; } start_flag = 1; printf("RCA_%d: thrinit ok\n", pthread_self()); return 1; } int thrdone(RCAINFO info) { if (start_flag) { start_flag = 0; tpend(); } printf("RCA_%d: thrdone ok\n", pthread_self()); return 0; } int thrmain(RCAINFO info) { struct msg header; int n; long len; char *sndbuf; char buf[8192]; buf[0] = 0; n = read(info->fd, &header, sizeof(struct msg)); if (n != sizeof(struct msg)) { printf("RCA_%d: read header fail = %d\n", pthread_self(), n); return -1; } len = ntohl(header.len); n = read(info->fd, buf, len); if (n != len) { printf("RCA_%d: read data fail = %d\n", pthread_self(), n); return -1; } /* ----------------------------------------------- */ if (!start_flag) { n = tpstart(NULL); if (n < 0) { printf("RCA_%d: tpstart fail, tperrno = %d\n", pthread_self(), tperrno); return -1; } start_flag = 1; } sndbuf = (char *)tpalloc("CARRAY", NULL, len + 1); if (sndbuf == NULL) { printf("RCA_%d: tpalloc fail, tperrno = %d\n", pthread_self(), tperrno); return -1; } memcpy(sndbuf, buf, len); n = tpcall(header.svcname, sndbuf, len, &sndbuf, &len, 0); if (n < 0) { printf("RCA_%d: tpcall fail, tperrno = %d\n", pthread_self(), tperrno); tpfree(sndbuf); return -1; } memcpy(buf, sndbuf, len); header.len = htonl(len); tpfree(sndbuf); /* ----------------------------------------------- */ write(info->fd, &header, sizeof(struct msg)); write(info->fd, buf, len); return 0; }