전체 소스중 일부만 발췌하였으며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);
}