프로세스의 이해와 활용
다중 접속 서버의 구현 방법들
- 멀티프로세스 기반 서버 : 다수의 프로세스를 생성하는 방식으로 서비스 제공
- 멀티플렉싱 기반 서버 : 입출력 대상을 묶어서 관리하는 방식으로 서비스 제공
- 멀티쓰레딩 기반 서버 : 클라이어언트의 수만큼 쓰레드를 생성하는 방식으로 서비스 제공
다중 접속 서버란 둘 이상의 클라이언트에게 동시에 접속을 허용하여, 동시에 둘 이상의 클라이언트에게 서비스를 제공하는 서버를 의미한다.
프로세스와 프로세스의 ID
프로세스란?
- 간단하게 실행 중인 프로그램을 뜻한다.
- 실행중인 프로그램에 관련된 메모리, 리소스 등을 총칭하는 의미이다.
- 멀티프로세스 운영체제는 둘 이상의 프로세스를 동시에 생성 가능하다.
fork 함수의 호출을 통한 프로세스의 생성
#include <unistd.h> pid_t fork(void); 성공 시 프로세스 ID, 실패시 -1 반환
fork 함수가 호출되면, 호출한 프로세스가 복사되어 fork 함수가 호출되면, 호출한 프로세스가 복사되어 fork 함수 호출 이후를 각각의 프로세스가 독립적으로 실행하게 된다.

fork 함수 호출 이후의 반환 값은 다음과 같다. 따라서 반환 값의 차를 통해서 부모 프로세스와 자식 프로세스의 프로그램 흐름을 구분하게 된다.
fork 함수를 호출한 프로세스는 부모 프로세스
fork 함수의 호출을 통해서 생성된 프로세스는 자식 프로세스
프로세스 & 좀비 프로세스
좀비 프로세스란?
- 실행이 완료되었음에도 불구하고, 소멸되지 않은 프로세스
- 프로세스도 main함수가 반환되면 소멸되어야 한다.
- 소멸되지 않았다는 것은 프로세스가 사용한 리소스 메모리 공간에 여전히 존재한다는 의미이다.
좀비 프로세스의 생성 원인
- 자식 프로세스가 종료되면서 반환하는 상태 값이 부모 프로세스에게 전달되지 않으면 해당 프로세스는 소멸되지 않고 좀비가 된다.
- 인자를 전달하면서 exit를 호출하는 경우
- main함수에서 return문을 싱행하면서 값을 반환하는 경우
자식 프로세스의 종료 상태 값이 운영체제에 전달되는 경로
- 인자를 전달하면서 exit를 호출하는 경우
- main함수에서 return문을 실행하면서 값을 반환하는 경우
좀비 프로세스의 생성 확인
#include <stdio.h> #include <unistd.h> int main(int argc, char *argv[]) { pid_t pid=fork(); if(pid==0) // if Child Process { puts("Hi I'am a child process"); } else { printf("Child Process ID: %d \n", pid); sleep(30); // Sleep 30 sec. } if(pid==0) puts("End child process"); else puts("End parent process"); return 0; }
14행 : 자식 프로세스의 ID를 출력하고 있다. 이 값을 통해서 자식 프로세스의 상태(좀비인지 아닌지)를 확인 할 수 있다.
15행 : 30초간 부모 프로세스를 멈추기 위한 코드가 삽입되어 있다. 부모 프로세스가 종료되면 좀비 상태에 있던 자식 프로세스도 함께 소멸되기 때문에 좀비의 확인을 위해서는 부모 프로세스의 종료를 지연시킬 필요가 있다.
실행결과

좀비 프로세스의 소멸 : wait 함수의 사용
자식 프로세스의 소멸을 위해서는 부모 프로세스가 자식 프로세스의 전달 값을 요청해야함. 요청 방법에는 두가지 가 있는데, 그 중 하나는 wait함수를 사용 하는 것이다.
include <sys/wait.h> pid_t wait(int *statloc); 성공시 종료된 자식 프로세스의 ID, 실패시 -1 반환
WIFEXITED 자식프로세스가 정상 종료한 경우 '참(ture)'을 반환한다.
WEXITSTATUS 자식 프로세스이 전달 값을 반환한다.
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> int main(int argc, char *argv[]) { int status; pid_t pid=fork(); if(pid==0) { return 3; } else { printf("Child PID: %d \n", pid); pid=fork(); if(pid==0) { exit(7); } else { printf("Child PID: %d \n", pid); wait(&status); if(WIFEXITED(status)) printf("Child send one: %d \n", WEXITSTATUS(status)); wait(&status); if(WIFEXITED(status)) printf("Child send two: %d \n", WEXITSTATUS(status)); sleep(30); // Sleep 30 sec. } } return 0; }
해설
9,13 행 : 9행에서 생성된 자식 프로세스 13행에서 보이듯이 main함수 내에서 return문 실행을 통해 종료하게 된다.
18, 21행 : 18행에서 생성된 자식 프로세스는 21행에서 보이듯이 exit 함수 호출을 통해서 종료하게 된다.
26행 : wait 함수를 호출하고 있다.
27행 : 27행의 매크로 함수 WIFEXITED를 통해서 자식 프로세스의 정상종료 여부를 확인.
30~32행 : 앞서 생성한 자식 프로세스가 두개이므로 또 한번의 wait 함수 호출과 매크로 함수와 호출을 진행하고 있다.
33행 : 부모 프로세스의 종료를 멈추기 위해서 삽입한 코드이다. 이 순간에 여러분은 자식 프로세스의 상태를 확인하면 된다.
실행결과

좀비프로세스의 소멸2: waitpid 함수의 사용
#include <sys/wait.h> pid_t waitpid(pid_t pid, int *statloc, int options); 성공 시 종료된 자식 프로세스의 ID(또는 0), 실패시 -1반환
pid : 종료를 확인하고자 하는 자식 프로세스의 ID전달, 이를 대신해서 -1을 전달하면 wait함수와 마찬가지로 임의의 자식 프로세스가 종료되기를 기다린다.
statloc wait : 함수의 매개변수 statloc과 동일한 의미로 사용된다.
options : 헤더파일 sys/wait.h에 선언된 상수 WNOHANG을 인자로 전달하면, 종료된 자식 프로세스가 존재하지 않아도 블로킹 상태에 있지 않고, 0을 반환하면서 함수를 빠져나온다.
#include <stdio.h> #include <unistd.h> #include <sys/wait.h> int main(int argc, char *argv[]) { int status; pid_t pid=fork(); if(pid==0) { sleep(15); return 24; } else { while(!waitpid(-1, &status, WNOHANG)) { sleep(3); puts("sleep 3sec."); } if(WIFEXITED(status)) printf("Child send %d \n", WEXITSTATUS(status)); } return 0; }
12행 :자식 프로세스의 종료를 늦추기 위해서 sleep 함수를 호출하고 있다. 이로 인해서 약 15초간의 지연이 생긴다.
17행 : while문 애에서 waitpid 함수를 호출하고 있다. 세번째 인자로 WNOHANG를 전달하였으니, 종료된 자식 프로세스가 없으면 0을 반환한다.

'TCP&IP' 카테고리의 다른 글
DB 만들어보기 (0) | 2024.09.06 |
---|---|
TCP&IP 제13장 다양한 입출력 함수들 (0) | 2024.09.05 |
TCP/IP 9장 소켓의 다양한 옵션 (0) | 2024.09.05 |
TCP/IP 8장 도메인 이름과 인터넷 주소 (0) | 2024.09.05 |
TCP/IP 5장 기반서버/클라이언트 2 (0) | 2024.09.04 |
댓글