예제
본 장에서는 TCPGWTHR의 각 역할에 대한 예제를 설명한다.
1. 서버 모드 Outbound 서비스 호출
서버 모드 TCPGWTHR를 통해 리모트에서 Tmax의 서비스를 요청하는 예제이다.
프로그램 구성은 다음과 같다.
구분 | 파일명 |
---|---|
환경 파일 |
tmax.m |
TCPGWTHR |
usermain.c |
리모트 노드 |
tcpcli1.c |
Tmax 노드 |
svr.c |
1.1. 환경 파일
<tmax.m>
*DOMAIN res SHMKEY = 88000, MINCLH = 1, MAXCLH = 1, TPORTNO = 8888 *NODE node1TMAXDIR=”/home/tmax”, APPDIR=”/home/tmax/appbin” *SVRGROUP svg1NODENAME = node1 *SERVER tcpgwlsn SVGNAME = svg1, MIN=1, MAX=1, SVRTYPE = CUSTOM_GATEWAY, RESTART = N, CLOPT="-- -P 9777 -N 3 -k 91000" tcpgwhdr1 SVNAME = svg1, MIN=3, MAX=3, SCHEDULE=RR, SVRTYPE=CUSTOM_GATEWAY, CPC=10, TARGET = tcpgwhdr, CLOPT="-- -P 9777 -N 10 -s –L tcpgwlsn" svr SVGNAME = svg1 *SERVICE TESTSVC SVRNAME = svr
1.2. TCPGWTHR
<usermain.c>
#ifdef _WIN32 #include <winsock2.h> #include <windows.h> #include <io.h> #else #include <pthread.h> #endif #include <tcphdr.h> char sndbuf[4096]; char rcvbuf[4096]; long sndlen, rcvlen; int errflag; extern int _portno; int user_thrmain(WORKTHRINFO *winfo, int server) { if (server) server_process(winfo); else client_process(winfo); return 1; } int server_process(WORKTHRINFO *winfo) { int n, len, flags; char tmp[10]; memset(tmp, 0x00, sizeof(tmp)); while (1) { n = tcpgw_select(winfo, 0, 0); if (n < 0) return -1; printf("tcpgw_select: n = %d\n", n); /* request ffrom tmax service & client */ switch(n) { case WTHR_TMAX_REQUEST: len = tcpgw_get_svcdata(winfo, &rcvbuf[4], &errflag, &flags); if (len < 0) { if (len == WTHR_CLIENT_CLOSE) return -1; printf("service data read failed\n"); return -1; } printf("TMAX_REQUEST: length = %d\n", len); /* no reply */ if (flags) n = tcpgw_tpreply(winfo, rcvbuf, n, 0); sprintf(tmp, "%04d", len); memcpy(rcvbuf, tmp, 4); len += 4; n = tcpgw_write(winfo->fd, rcvbuf, len); if (n < 0) { printf("remote client closed\n"); return -1; } printf("TMAX_REQUEST: remote write ok [%d]\n", n); n = tcpgw_read(winfo->fd, tmp, 4, 0, 0); if (n <= 0) { printf("remote client closed\n"); return -1; } len = atoi(tmp); if (len <= 0) break; printf("TMAX_REQUEST: read length = %d\n", len); n = tcpgw_read(winfo->fd, rcvbuf, len, 0, 0); if (n <= 0) { printf("remote client closed\n"); return -1; } if (flags) { printf("USER_REQUEST: service call length = %d\n", n); flags = 1; n = tcpgw_tpcall(winfo, "TESTSVC", rcvbuf, n, rcvbuf, &rcvlen); } else { printf("TMAX_REQUEST: tpcall reply length = %d\n", n); n = tcpgw_tpreply(winfo, rcvbuf, n, 0); } if (n < 0) { printf("tmax down\n"); return -1; } break; case WTHR_USER_REQUEST: n = tcpgw_read(winfo->fd, tmp, 4, 0, 0); if (n <= 0) { printf("remote client closed\n"); return -1; } len = atoi(tmp); if (len <= 0) break; printf("USER_REQUEST: read length = %d\n", len); n = tcpgw_read(winfo->fd, sndbuf, len, 0, 0); if (n <= 0) { printf("remote client closed\n"); return -1; } printf("USER_REQUEST: service call length = %d\n", n); n = tcpgw_tpcall(winfo, "TESTSVC", sndbuf, n, rcvbuf, &rcvlen); if (n < 0) { printf("service failed: [%d]\n", n); } sprintf(tmp, "%04d", rcvlen); memcpy(sndbuf, tmp, 4); memcpy(&sndbuf[4], rcvbuf, rcvlen); len = rcvlen + 4; printf("USER_REQUEST: service reply length = %d\n", len); n = tcpgw_write(winfo->fd, sndbuf, len); if (n < 0) { printf("remote client closed\n"); return -1; } break; case WTHR_SELECT_TIMEOUT: /* timeout process */ break; } } return 1; } int client_process(WORKTHRINFO *winfo) { int fd, portno; char ipaddr[20]; portno = tcpgw_getaddr_from_winfo(winfo, ipaddr); /* socket connect */ while (1) { fd = tcpgw_network_connect(ipaddr, portno, 0); if (fd > 0) break; printf("remote connect failed\n"); #ifdef _WIN32 Sleep(10000); #else sleep(10); #endif continue; } winfo->fd = fd; /* must save */ server_process(winfo); return 1; }
1.3. 리모트 노드
<tcpcli1.c>
#include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef _WIN32 #include <winsock2.h> #include <windows.h> #include <io.h> #else #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> #endif #ifdef _WIN32 #define GW_ADDR "host" #else #define GW_ADDR "10.10.10.10" #endif #define GW_PORT 9777 #define NUM_LOOP 1 #define MAX_MSG 496 #if (defined(_SOCK1) || defined(_SOCK11)) #define _LOBYTE 1 #define _HIBYTE 1 #else #define _LOBYTE 2 #define _HIBYTE 0 #endif #ifdef _WIN32 int winsock_init(void) { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(_LOBYTE, _HIBYTE); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { /* Tell the user that we couldn't find a usable */ /* WinSock DLL. */ printf("0060 Winsock startup error\n"); return -1; } /* Confirm that the WinSock DLL supports 2.0.*/ /* Note that if the DLL supports versions greater */ /* than 2.0 in addition to 2.0, it will still return */ /* 2.0 in wVersion since that is the version we */ /* requested. */ if (LOBYTE(wsaData.wVersion) != _LOBYTE || HIBYTE(wsaData.wVersion) != _HIBYTE) { /* Tell the user that we couldn't find a usable */ /* WinSock DLL. */ WSACleanup(); printf("0061 Winsock version check error\n"); return -1; } /* The WinSock DLL is acceptable. Proceed. */ return 1; } #endif int _network_connect(char *host, int port) { struct sockaddr_in serv_addr; unsigned int inaddr; struct hostent *hp; int i, fd; memset((char *) &serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); if ((inaddr = (unsigned int) inet_addr(host)) != -1) { memcpy((char *) &serv_addr.sin_addr, (char *) &inaddr, sizeof(struct in_addr)); } else { if ((hp = gethostbyname(host)) == NULL) { printf("COM3412: host name error: %s ", host); return(-1); } memcpy((char *) &serv_addr.sin_addr, hp->h_addr, hp->h_length); } if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("COM3413: can't open stream socket"); return -1; } if (connect(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) >= 0) return fd; close(fd); return -1; } int main(int argc, char *argv[]) { char gw_addr[256], tmp[10]; int gw_port, fd, i, n, len, num_loop; char data[MAX_MSG]; strcpy(gw_addr, GW_ADDR); gw_port = GW_PORT; num_loop = NUM_LOOP; if (argc == 2) { num_loop = atoi(argv[1]); } else if (argc == 3) { gw_port = atoi(argv[1]); num_loop = atoi(argv[2]); } else if (argc >= 4) { strcpy(gw_addr, argv[1]); gw_port = atoi(argv[2]); num_loop = atoi(argv[3]); } #ifdef _WIN32 winsock_init(); #endif fd = _network_connect(gw_addr, gw_port); if (fd < 0) { printf("Connect to (%s:%d) fail \n", gw_addr, gw_port); return -1; } sleep(5); memset(data, 0x00, MAX_MSG); for (i=0; i<num_loop; i++) { sprintf(&data[4], "Msg(%d) produced by PID(%d)", i, getpid()); len = strlen(&data[4]); sprintf(tmp, "%04d", len); memcpy(data, tmp, 4); len += 4; n = send(fd, data, len, 0); if (n != len) { printf("Sent only %d / %d bytes\n", n, len); return -1; } len = 4; n = recv(fd, data, len, 0); if (n != len) { printf("Recv error %d\n", n); return -1; } memcpy(tmp, data, 4); tmp[4] = 0x00; len = atoi(tmp); if (len <= 0) { printf("Pid (%d) received %d bytes\n", getpid(), n); continue; } n = recv(fd, data, len, 0); if (n != len) { printf("Recv error %d\n", n); return -1; } printf("Pid (%d) received %d bytes\n", getpid(), n); sleep(5); } return 1; }
2. 서버 모드 Inbound 서비스 호출
서버 모드 TCPGWTHR를 통해 Tmax에서 리모트의 서비스를 요청하는 예제이다.
프로그램 구성은 다음과 같다.
구분 | 파일명 |
---|---|
환경 파일 |
tmax.m, tcpgwthr.cfg |
TCPGWTHR |
usermain.c (파일의 예제는 서버 모드 Outbound 서비스 호출에서 설명했으므로 본 절에서는 생략한다.) |
리모트 노드 |
tcpcli2.c |
Tmax 노드 |
toupper.c |
2.1. 환경 파일
<tmax.m>
*DOMAIN Res SHMKEY = 88000, MINCLH = 1, MAXCLH = 1, TPORTNO = 8888 *NODE node1TMAXDIR=”/home/tmax”, APPDIR=”/home/tmax/appbin” *SVRGROUP svg1NODENAME = node1 *SERVER tcpgwlsn SVGNAME = svg1, MIN=1, MAX=1, SVRTYPE = CUSTOM_GATEWAY, RESTART = N, CLOPT="-- -P 9777 -N 3 -k 91000 -F /home/tmax/appbin/tcpgwthr.cfg" tcpgwhdr1 SVNAME = svg1, MIN=3, MAX=3, SCHEDULE=RR,SVRTYPE=CUSTOM_GATEWAY, CPC= 10, TARGET = tcpgwhdr, CLOPT="-- -P 9777 -N 10 -s –L tcpgwlsn" *SERVICE svcgw SVRNAME = tcpgwhdr1
<tcpgwthr.cfg>
# Client IP Server Port Client ID 10.10.10.10 9777 SVR0001
2.2. 리모트 노드
<tcpcli2.c>
#include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef _WIN32 #include <winsock2.h> #include <windows.h> #include <io.h> #else #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> #endif #ifdef _WIN32 #define GW_ADDR "host" #else #define GW_ADDR "10.10.10.10" #endif #define GW_PORT 9777 #define NUM_LOOP 1 #define MAX_MSG 496 #if (defined(_SOCK1) || defined(_SOCK11)) #define _LOBYTE 1 #define _HIBYTE 1 #else #define _LOBYTE 2 #define _HIBYTE 0 #endif #ifdef _WIN32 int winsock_init(void) { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(_LOBYTE, _HIBYTE); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { /* Tell the user that we couldn't find a usable */ /* WinSock DLL. */ printf("0060 Winsock startup error\n"); return -1; } /* Confirm that the WinSock DLL supports 2.0.*/ /* Note that if the DLL supports versions greater */ /* than 2.0 in addition to 2.0, it will still return */ /* 2.0 in wVersion since that is the version we */ /* requested. */ if (LOBYTE(wsaData.wVersion) != _LOBYTE || HIBYTE(wsaData.wVersion) != _HIBYTE) { /* Tell the user that we couldn't find a usable */ /* WinSock DLL. */ WSACleanup(); printf("0061 Winsock version check error\n"); return -1; } /* The WinSock DLL is acceptable. Proceed. */ return 1; } #endif int _network_connect(char *host, int port) { struct sockaddr_in serv_addr; unsigned int inaddr; struct hostent *hp; int i, fd; memset((char *) &serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); if ((inaddr = (unsigned int) inet_addr(host)) != -1) { memcpy((char *) &serv_addr.sin_addr, (char *) &inaddr, sizeof(struct in_addr)); } else { if ((hp = gethostbyname(host)) == NULL) { printf("COM3412: host name error: %s ", host); return(-1); } memcpy((char *) &serv_addr.sin_addr, hp->h_addr, hp->h_length); } if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("COM3413: can't open stream socket"); return -1; } if (connect(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) >= 0) return fd; close(fd); return -1; } int main(int argc, char *argv[]) { char gw_addr[256], tmp[10]; int gw_port, fd, i, n, len, num_loop; char data[MAX_MSG]; strcpy(gw_addr, GW_ADDR); gw_port = GW_PORT; if (argc == 2) { gw_port = atoi(argv[1]); } #ifdef _WIN32 winsock_init(); #endif fd = _network_connect(gw_addr, gw_port); if (fd < 0) { printf("Connect to (%s:%d) fail \n", gw_addr, gw_port); return -1; } memset(data, 0x00, MAX_MSG); while (1) { len = 4; n = recv(fd, data, len, 0); if (n != len) { printf("Recv error %d\n", n); return -1; } memcpy(tmp, data, 4); tmp[4] = 0x00; len = atoi(tmp); if (len <= 0) { printf("Pid (%d) received %d bytes\n", getpid(), n); continue; } n = recv(fd, &data[4], len, 0); if (n != len) { printf("Recv error %d\n", n); return -1; } printf("Pid (%d) received %d bytes\n", getpid(), n); len = n + 4; for (i = 4; i < len; i++) data[i] = toupper(data[i]); n = send(fd, data, len, 0); if (n != len) { printf("Sent only %d / %d bytes\n", n, len); return -1; } printf("Pid (%d) sended %d bytes\n", getpid(), len-4); } return 1; }
2.3. Tmax 노드
<toupper.c>
#include <stdlib.h> #include <string.h> #include <usrinc/atmi.h> #include <usrinc/hlinkapi.h> main(int argc, char *argv[]) { char *sndbuf, *rcvbuf; long rcvlen, sndlen; int ret, len; TPGWINFO_T gwinfo; strcpy(gwinfo.svc, "SVR0001"); if (argc != 2) { printf("Usage: toupper string\n"); exit(1); } if ( (ret = tmaxreadenv( "tmax.env","TMAX" )) == -1 ){ printf( "tmax read env failed\n" ); exit(1); } if (tpstart((TPSTART_T *)NULL) == -1){ printf("tpstart failed\n"); exit(1); } if ((sndbuf = (char *)tpalloc("CARRAY", NULL, 0)) == NULL) { printf("sendbuf alloc failed !\n"); tpend(); exit(1); } if ((rcvbuf = (char *)tpalloc("CARRAY", NULL, 0)) == NULL) { printf("recvbuf alloc failed !\n"); tpfree((char *)sndbuf); tpend(); exit(1); } memcpy(sndbuf, &gwinfo, TPGWINFO_SIZE); strcpy(sndbuf+TPGWINFO_SIZE, argv[1]); len = strlen(argv[1]); len += TPGWINFO_SIZE; if(tpcall("svcgw", sndbuf, len, &rcvbuf, &rcvlen, 0)==-1){ printf("Can't send request to service svcgw - %d\n", tperrno); tpfree((char *)sndbuf); tpfree((char *)rcvbuf); tpend(); exit(1); } printf("send data: %s\n", sndbuf+TPGWINFO_SIZE); printf("recv data: %s\n", rcvbuf); tpfree((char *)sndbuf); tpfree((char *)rcvbuf); tpend(); }
3. 클라이언트 모드 Inbound 서비스 호출
클라이언트 모드 TCPGWTHR을 통해 Tmax에서 리모트의 서비스를 요청하는 예제이다.
프로그램 구성은 다음과 같다.
구분 | 파일명 |
---|---|
환경 파일 |
tmax.m, tcpgwthr.cfg |
TCPGWTHR |
usermain.c (파일의 예제는 서버 모드 Outbound 서비스 호출에서 설명했으므로 본 절에서는 생략한다.) |
리모트 노드 |
tcpsvr2.c |
Tmax 노드 |
toupper.c (파일의 예제는 서버 모드 Inbound 서비스 호출에서 설명했으므로 본 절에서는 생략한다.) |
3.1. 환경 파일
<tmax.m>
*DOMAIN res SHMKEY = 88000, MINCLH = 1, MAXCLH = 1, TPORTNO = 8888 *NODE node1 TMAXDIR = "/home/tmax", APPDIR = "/home/tmax/appbin" *SVRGROUP svg1 NODENAME = node1 *SERVER clihdrshm SVGNAME = svg1, MIN = 1, MAX = 1, SVRTYPE = CUSTOM_GATEWAY, CLOPT = "-- -N 10 -k 91000 -F /home/tmax/appbin/tcpgwthr.cfg" tcpgwhdr1 SVGNAME svg1, MIN = 10, MAX = 10, SVRTYPE = CUSTOM_GATEWAY, CPC = 9, SCHEDULE = RR, TARGET = tcpgwhdr, CLOPT = "-- -k 91000 –L clihdrshm -F /home/tmax/appbin/tcpgwthr.cfg" *SERVICE svcgw SVRNAME = tcpgwhdr1
3.2. 리모트 노드
<tcpsvr2.c>
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #ifdef _WIN32 #include <winsock2.h> #include <windows.h> #include <io.h> #else #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> #endif #define GW_PORT 9777 #define NUM_LOOP 1 #define MAX_MSG 496 #if (defined(_SOCK1) || defined(_SOCK11)) #define _LOBYTE 1 #define _HIBYTE 1 #else #define _LOBYTE 2 #define _HIBYTE 0 #endif #define max(a,b) ((a) > (b) ? (a) : (b)) int listen_fd = -1; int work_fd; fd_set readfds; int maxfd = 0; #ifdef _WIN32 int winsock_init(void) { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(_LOBYTE, _HIBYTE); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { /* Tell the user that we couldn't find a usable */ /* WinSock DLL. */ printf("0060 Winsock startup error\n"); return -1; } /* Confirm that the WinSock DLL supports 2.0.*/ /* Note that if the DLL supports versions greater */ /* than 2.0 in addition to 2.0, it will still return */ /* 2.0 in wVersion since that is the version we */ /* requested. */ if (LOBYTE(wsaData.wVersion) != _LOBYTE || HIBYTE(wsaData.wVersion) != _HIBYTE) { /* Tell the user that we couldn't find a usable */ /* WinSock DLL. */ WSACleanup(); printf("0061 Winsock version check error\n"); return -1; } /* The WinSock DLL is acceptable. Proceed. */ return 1; } #endif int network_listen(int portno) { int fd; struct sockaddr_in serv_addr; int on; if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) return(-1); on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0) { printf("0062 setsockopt error: SO_REUSEADDR"); } memset((char *) &serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons((unsigned short)portno); if (bind(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { close(fd); return(-2); } if (listen(fd, 50) < 0) { close(fd); return(-3); } return(fd); } int network_accept(int listenfd) { socklen_t len; int fd, on; struct sockaddr_in cli_addr; len = sizeof(cli_addr); fd = accept(listenfd, (struct sockaddr *) &cli_addr, &len); if (fd < 0) return(-1); /* often errno=EINTR, if signal caught */ return(fd); } int main(int argc, char *argv[]) { char gw_addr[256]; int gw_port, fd, i, n, len, num_loop; char data[MAX_MSG], *sndbuf; gw_port = GW_PORT; if (argc == 2) { gw_port = atoi(argv[1]); } #ifdef _WIN32 winsock_init(); #endif listen_fd = network_listen(gw_port); if (listen_fd < 0) { printf("Connect to (%d) fail \n", gw_port); return -1; } FD_ZERO(&readfds); FD_SET(listen_fd, &readfds); maxfd = listen_fd; while (1) { errno = 0; n = select(maxfd + 1, &readfds, NULL, NULL, NULL); if (n < 0) { if (errno == EINTR) { /* signal is caught */ continue; } else { printf("0080 select error"); return -1; } } if (FD_ISSET(listen_fd, &readfds)) { if ((fd = network_accept(listen_fd)) < 0) { printf("0043 socket accept error"); continue; } else { work_fd = fd; FD_SET(fd, &readfds); maxfd = max(maxfd, fd); } } if (FD_ISSET(work_fd, &readfds)) { service_process(work_fd); FD_CLR(work_fd, &readfds); close(work_fd); } } return 1; } int service_process(int fd) { int i, n, len; char tmp[10]; char data[MAX_MSG]; len = 4; n = recv(fd, data, len, 0); if (n != len) { printf("Recv error %d\n", n); return -1; } memcpy(tmp, data, 4); tmp[4] = 0x00; len = atoi(tmp); if (len <= 0) { printf("Pid (%d) received %d bytes\n", getpid(), n); return 1; } n = recv(fd, &data[4], len, 0); if (n != len) { printf("Recv error %d\n", n); return 1; } printf("Pid (%d) received %d bytes\n", getpid(), n); len = n + 4; for (i = 4; i < len; i++) data[i] = toupper(data[i]); n = send(fd, data, len, 0); if (n != len) { printf("Sent only %d / %d bytes\n", n, len); return 1; } printf("Pid (%d) sended %d bytes\n", getpid(), len-4); return 1; }