TCPIP

2013.07.04_멀티태스킹 테스트

성엽이 2013. 7. 5. 00:16

 

 

 멀티태스킹

 멀티태스킹 : fork() 함수를 이용하여서 1 Client <-> 1 Server(자식서버) , 독립적인 1:1 형태로 통신을 하는 방법이다.

 

 fork() 함수란? 

 현재 실행되는 프로세스에 대해 복사본 프로세스를 생성합니다.

 

fork()함수를 호출하고 성공하면 pid 변수값만 다른 완전히 똑 같은 프로세스가 생성됩니다. 그러므로 지금 프로그램이 원래 실행되었던 부모 프로세스인지, 아니면 새로 생성된 자식 프로세스인지는 fork()에서 반환한 값으로 확인합니다.

헤더 unistd.h
형태

pid_t fork(void);  // 여기서 pid_t 는 unsigned int 형

반환

pid_t 실행에 실패하면 -1 을 반환. 부모에게는 새로 생성된 자식 프로세스 PID가 반환되며, 자식 프로세스에는 0이 반환됩니다

 

 예제 :

원래 실행되었던 부모 프로세스 fork()로 생성된 자식 프로세스
int main()
{
  int   counter  = 0;
  pid_t pid;

  printf( "작식 프로세스 생성");
  pid   = fork(); ---> 자식 프로세서 생성

  ---> pid 값은 자식 프로세스의 pid 값

  switch( pid)
  {
    case -1  :
    {
      printf( "자식 프로세스 생성 실패\n");
      return -1;
    }
    case 0   :
    {
      printf( "저는 자식 프로세스....\n");
      while( 1 )
      {
        printf( "자식: %d\n", counter--);
        sleep( 1);
      }
    }
    default  :
    {
      printf( "저는 부모 프로세스로..");
      printf( "자식 프로세스의 pid는..", pid);
      while( 1 )
      {
        printf( "부모: %d\n", counter++);
        sleep( 1);
      }
    }
  }
}
int main()
{
  int   counter  = 0;
  pid_t pid;


---> 부모와 똑 같은 프로세스가 그대로 복사되므로
---> 전역 변수 값에서 로컬 변수 값까지 모두
---> 복사됩니다.
---> 대신에 딱 하나, pid 값만 0 값을 갖습니다.

  switch( pid)
  {
    case -1  :
    {
      printf( "자식 프로세스 생성 실패\n");
      return -1;
    }
    case 0   :
    {
      printf( "저는 자식 프로세스로....\n");
      while( 1 )
      {
        printf( "자식: %d\n", counter--);
        sleep( 1);
      }
    }
    default  :
    {
      printf( "저는 부모 프로세스로...\n");
      printf( "자식 프로세스의 pid는...", pid);
      while( 1 )
      {
        printf( "부모: %d\n", counter++);
        sleep( 1);
      }
    }
  }
}

 

 

 

 #include <stdio.h>      // pritnf, fprintf
#include <sys/socket.h>    // socket, bind, connect
#include <arpa/inet.h>    // sockaddr_in, inet_ntoa
#include <stdlib.h>      // atoi
#include <string.h>      // memset
#include <unistd.h>      // close

#define  MAXPENDING  5    // Maximum outstanding connection requests

int main ()
{
  int  servSock;            // Socket descriptor for server
  int  clntSock;            // Socket descriptor for client
  struct  sockaddr_in  echoServAddr;  // Local address
  struct  sockaddr_in  echoClntAddr;  // Client address
  unsigned short  echoServPort;    // Server port number
  unsigned int  clntLen;      // Length of client address data structure
  int  iRet;
  unsigned char  ucBuffer[500];
  pid_t ui_MomID;

  ui_MomID = getpid();
  
  echoServPort = 9999;        // Server Port Number

  
  // 1. 소켓 생성(랑데뷰 소켓)  Create socket for incoming connections
  servSock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
    // Protocol Family_Internet
  if (servSock < 0)  // error
  {
    printf ("socket() failed\n");
    return 0;
  }
  
  
  // 2. 구조체 생성  Construct local address structure
  memset ( &echoServAddr, 0sizeof(echoServAddr) );  // Zero out structure
    // memory setting ( 주소 , 채울 숫자, 몇개 )
  echoServAddr.sin_family = AF_INET;          // Internet address family
  echoServAddr.sin_addr.s_addr = htonl (INADDR_ANY);  // Any incoming interface
    // host to network long ( 크기 ) Big Endian 으로 바꿔주는 함수 
    // INADDR_ANY 는 0으로 define 되어 있다 ( 자동:클라이언트를 만들때 )
    // INADDR_ANY 대신에 내 IP의 실제 주소를 넣는 방법도 있다 ( 수동:서버를 만들때 )
  echoServAddr.sin_port = htons (echoServPort);    // Local port (2 byte)
    // host to network short ( 크기 ) Big Endian 으로 바꿔주는 함수 

  
  // 3. BIND 소켓에 구조체를 적용  Bind to the local address
  iRet = bind(servSock, (struct sockaddr*) &echoServAddr, sizeof (echoServAddr));
    // 신형을 구형으로 바꿈 = casting 연산 
  if (iRet < 0)  // error
  {
    printf ("bind() failed\n");
    close (servSock);
    return 0;
  }
  
  // 4. LISTEN   Mark the socket so it will listen for incoming connections
  iRet = listen(servSock, MAXPENDING);
    //   MAXPENDING 최대 동시 접속자 수
  if (iRet < 0)
  {
    printf ("listen() failed\n");
    close (servSock);
    return 0;
  }
  
  while (1)
  {
    if(ui_MomID == getpid())
    {
      // 5. ACCEPT  Wait for a client to connect
      clntLen = sizeof (echoClntAddr);
        // Set the size of the in-out parameter
      clntSock = accept (servSock, (struct sockaddr *) &echoClntAddr, &clntLen);
        // Communication Socket (client 의 정보가 저장)
      if (clntSock < 0)
      {
        printf ("accept() failed\n");
        return 0;
      }
      
      // clntSock is connected to a client
      printf ("Handling client ip %s\n", inet_ntoa(echoClntAddr.sin_addr));
      printf ("Handling client port %d\n", ntohs(echoClntAddr.sin_port)); 
    
      fork();  // 서버를 복제함.
      
      if(ui_MomID == getpid())  // 부모에게는 새로 생성된 자식 프로세스 PID가 반환되며, 자식 프로세스에는 0이 반환된다.

      {
        close(clntSock);  // 부모서버이므로 clntSock 을 닫아준다.
      }
      else
      {
        close(servSock);  // 자식서버이므로 servSock 을 닫아준다.
      }
    }
    else
    {
      iRet = read (clntSock, ucBuffer, 499);    // client로부터 입력 대기 
      ucBuffer[iRet] = 0;
      write (1, ucBuffer, iRet);
      write (clntSock, ucBuffer, iRet);
      
      if ('q' == ucBuffer[0])   / q 로 서버끔.
      {
        close (servSock);
        break;
      }

    }  
  }
  
  close (servSock);
  close (clntSock);

  return 0;
}