본문 바로가기

IT Device Game

[창고] 단순한 fork 갯수 제한 및 pool 관리 예제



전체 소스중 일부만 발췌하였으며fork 후 따로 노는 자식들 갯수를 관리하여무작위로 fork를 늘려가는걸 막아야 할 경우를 위해 작성한 로직임


 

#define MAX_FORK_INT       6    // 최대 fork갯수

// 전역변수 선언
int status = 0;
int rtnvalue = 0;
int fork_count = 0;
pid_t fork_pid[MAX_FORK_INT];
pid_t temp_pid;

int main(int argc, char *argv[])
{
 int rtn, rcvlen, mtype;
    int sofd, tcpfd; 
    int i = 0;
    char makeMsg[100+1];
 char sDate[20+1];
 
 In_Child = 0;
   
    // 실행시 관리할 fork 갯수 및 상태 초기화
    for(i=0;i<MAX_FORK_INT;i++)
 {
     fork_pid[i] = 0;
    }
 
    // TCP 접속 환경 load  
 Tcp_Config();
 
 // 환경 변수 및 실행 환경 설정
 Batch_Init(argc, argv, "ONLINE");
 
 // 서버 소켓 생성
    sofd = OpenServerSocket (&TcpPortNo);
    if (sofd < 0)                                  
    {
  FRM_ERR("#%04d Socket Open Error....\n",  __LINE__);
     sleep  (5);
        Proc_Exit(-1);
    }
 
 while(1)
    {
        // SIGCHILD(자식종료)  신호를 받을 수 있게 시그널 설정
        signal  ( SIGCHLD, SigChld_Handler );   // 20101110
       
        // fotk count가 최대 허용보다 크면서 부모프로세스 이면
        // fork 카운트 초과여부를 SMS로 알려 모니터링 정보를 주고
        // 자식 및 부모 프로세스를 종료하여 혹시 모를 오류들을 클리어함
        // -> 관리프로세스가 10초 주기로 되살림
        if (fork_count > MAX_FORK_INT && In_Child == 0)  
        {
            Set_Date(sDate);
            memset(makeMsg, 0x00, sizeof(makeMsg));
                       
            sprintf(makeMsg, "%s fork_count[%d] 초과 오류!! %.2s%시%.2s분%.2s초",
                                        szExeName, fork_count, &sDate[8], &sDate[10], &sDate[12]);
            if (strlen(smsnum) > 9)               
                Send_Sms(smsnum, makeMsg);    
       Kill_Prog(szExeName, 3, 0);     // 자식종료 및 경우에 따라 부모 종료
       Proc_Exit (-1);                 // 부모 미종료시 대비해 주차
   }
   
        memset (cmesg, 0x00, sizeof (cmesg));
   
   tcpfd = AcceptSocket (sofd, 0, RemoteAddr, &RemotePort);
       
        // 소켓 Accept 오류 일경우, 오류가 EINTR 인 경우 Accept BLOCK 상태에서
        // 자식 종료로 강제로 깨어난 경우 에는 SIGCHILD 처리후 다시 Accept 상태로 진행
        // 다른 오류 일 경우 프로세스 종료
  if (tcpfd == D_ERR)
  {
            // 20101110
            if (errno == EINTR)
            {
                continue;
            }
            else
            {               
                sleep  (5);
                Log_Trace("#%04d Socket Accept Error....\n",  __LINE__);
                Proc_Exit (-1);
            }
        }
        sprintf(Swip, "%03u.%03u.%03u.%03u", RemoteAddr[0], RemoteAddr[1], RemoteAddr[2], RemoteAddr[3]);
       
        if(memcmp(Swip, "010.000.001.129", 15) != 0 && memcmp(Swip, "010.000.001.131", 15) != 0)
        {   
            Log_Trace ("#%04d [소켓접속OK][%03u.%03u.%03u.%03u:%u]\n",  __LINE__,
                    RemoteAddr[0], RemoteAddr[1], RemoteAddr[2], RemoteAddr[3],RemotePort);
        }
       
        rtn = fork ();
       
  if (rtn < 0)
  {
            FRM_ERR("%04d [FORK호출오류][%d][%d][%s]\n",  __LINE__,
                       rtn, errno, strerror(errno));
            Proc_Exit(-1);
        }
        if (rtn == 0)
  {
      In_Child = 1; //자식 일경우 1, 부모이면 0
     
            close (sofd);
            Srvfd = tcpfd;
            Child_Proc ();
            exit  (0);
        }
        // 20100408
        else
        {
            In_Child = 0;
           
            fork_count++;
           
            Log_Trace("#%04d 현재 fork_count[%d] \n",  __LINE__, fork_count);
           
            if (fork_count < 1)
                fork_count = 1;
           
            // fork 관리 정보에 비어있는 배열에 소켓FD를 셋팅함   
            if (fork_count <= MAX_FORK_INT)
            {
                for(i = 0; i < MAX_FORK_INT; i++)
                {
                    if(fork_pid[i] == 0)
                    {
                        fork_pid[i] = rtn;
                        break;
                    }
                }
            }
           
        }
        // end 20100408
       
        close (tcpfd);
    }
 return 0;
}

// 시그널 초기화 함수
void Sig_Init()
{
    /*------< Setup Signal >--------*/
    signal  ( SIGINT,  SIG_IGN );
    signal  ( SIGPIPE, SIG_IGN );
    signal  ( SIGQUIT, SigTerm_Handler );   // 20100408
    signal  ( SIGTTOU, SIG_IGN );
    signal  ( SIGILL,  SIG_IGN );
    signal  ( SIGHUP,  SigTerm_Handler );
#ifndef LINUX
    signal  ( SIGSYS , SigTerm_Handler );
#endif
    signal  ( SIGTERM, SigTerm_Handler );
    signal  ( SIGBUS,  SigTerm_Handler );
    signal  ( SIGSEGV, SigTerm_Handler );
}

// 종료 요건에 해당 되는 신호 일때 프로세스를 종료
static void SigTerm_Handler(int signo)
{
    FRM_ERR ("#%04d [SIGNAL RECEIVED..][%d]\n", __LINE__, signo);
    Proc_Exit(signo);
}

// 자식 종료 시그널이 왔을때 종료한 자식을 받아주고 -> 안받아 주면
// 받아줄때까지 defunct(좀비프로세스) 로 남음
// fork 관리 정보를 클리어함
static void SigChld_Handler(int signo)
{
    int i = 0, rtn = 0;
   
    Log_Trace ("#%04d 자식프로세스 종료 신호 수신[%d]\n", __LINE__, signo);
   
    if (In_Child == 0)           
    {
     for(i = 0; i < MAX_FORK_INT; i++)
        {
            if (fork_pid[i] != 0)
            {
                temp_pid = fork_pid[i];
                rtn = waitpid(temp_pid, &status, WNOHANG);
              
                if (rtn > 0)
                {                               
                    if (WIFEXITED(status))
                    {
                        rtnvalue = WEXITSTATUS(status);
                        Log_Trace("#%04d 자식프로세스 정상종료 rtn (%d) pid[%d]\n",
                                     __LINE__, rtnvalue, fork_pid[i]);
                       
                        fork_count--;
                        if(fork_count < 0)
                            fork_count = 0;
                        fork_pid[i] = 0;                    
                    }
                }
            }   
        }
    }
    else   
        Child_Exit(signo);
}

반응형