제4장 예제

내용 목차

4.1. 서버 모드 Outbound 서비스 호출
4.1.1. 환경 파일
4.1.2. TCPGWTHR
4.1.3. 리모트 노드
4.1.4. Tmax 노드
4.2. 서버 모드 Inbound 서비스 호출
4.2.1. 환경 파일
4.2.2. 리모트 노드
4.2.3. Tmax 노드
4.3. 클라이언트 모드 Inbound 서비스 호출
4.3.1. 환경 파일
4.3.2. 리모트 노드

본 장에서는 1장에서 설명한 TCPGWTHR의 각 역할에 대한 예제를 설명한다.

4.1. 서버 모드 Outbound 서비스 호출

서버 모드 TCPGWTHR를 통해 리모트에서 Tmax의 서비스를 요청하는 예제이다.

프로그램 구성은 다음과 같다.

구분파일명
환경 파일tmax.m
TCPGWTHRusermain.c
리모트 노드tcpcli1.c
Tmax 노드svr.c

4.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

4.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;
}

4.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;
}

4.1.4. Tmax 노드

< svr.c >

#include <stdio.h>
#include <usrinc/atmi.h>

TESTSVC(TPSVCINFO *msg)
{
  inti;
   
  printf("TESTSVC service is started!\n");
  sleep(1);
  printf("OUTPUT: data=%.*s\n", msg->len, msg->data);
  printf("TESTSVC service is stoped!\n");
  tpreturn(TPSUCCESS,0,(char *)msg->data, msg->len, 0);
}

4.2. 서버 모드 Inbound 서비스 호출

서버 모드 TCPGWTHR를 통해 Tmax에서 리모트의 서비스를 요청하는 예제이다.

프로그램 구성은 다음과 같다.

구분파일명
환경 파일tmax.m, tcpgwthr.cfg
TCPGWTHR

usermain.c

(파일의 예제는 “4.1. 서버 모드 Outbound 서비스 호출”에서 설명했으므로 본 절에서는 생략한다.)

리모트 노드tcpcli2.c
Tmax 노드toupper.c

4.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

4.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;
}

4.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();
}

4.3. 클라이언트 모드 Inbound 서비스 호출

클라이언트 모드 TCPGWTHR을 통해 Tmax에서 리모트의 서비스를 요청하는 예제이다.

프로그램 구성은 다음과 같다.

구분파일명
환경 파일tmax.m, tcpgwthr.cfg
TCPGWTHR

usermain.c

(파일의 예제는 “4.1. 서버 모드 Outbound 서비스 호출”에서 설명했으므로 본 절에서는 생략한다.)

리모트 노드tcpsvr2.c
Tmax 노드

toupper.c

(파일의 예제는 “4.2. 서버 모드 Inbound 서비스 호출”에서 설명했으므로 본 절에서는 생략한다.)

4.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

4.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;
}