본 글은 윤성우의 TCP/IP 소켓 프로그래밍 책을 참고하였습니다.

순서

I. 프로세스 기본개념

II. 프로세스 생성하기 (fork()함수)


주의!! 본 글에서 설명하는 멀티 프로세스 기반 서버는 Windows에는 지원하지 않는 Linux 방식입니다. 

 

I. 프로세스 기본개념


1. 다중접속 서버의 필요성

생각해보면, 기존에 우리가 소켓 프로그래밍의 함수를 나열해서 만든 서버는 큰 불편함이 있다. 

바로 연결 대기가 일렬로 된다는 것이다.

은행창구가 하나밖에 없는데 손님은 100명이 넘는 상황인 것이다.

어떻게 하면 모든 클라이언트에게 동시에 서비스를 제공할 수 있을까??
--> 다중접속 서버를 구현하자!

또한, CPU의 연산이 필요하지 않는 데이터의 송/수신만을 다루기 때문에,
다수의 클라이언트에게 동시에 서비스를 제공하는 것이 CPU를 효율적으로 사용할 수 있다.

 


2. 프로세스의 이해

프로세스 : "메모리 공간을 차지한 상태에서 실행중인 프로그램"

ex) 현재 컴퓨터에 실행한 프로그램들 전부 프로세스로 작동 중이다.

모든 프로그램은 실행하면 프로세스가 생성되고,
프로그램은 메인 메모리로 이동해서 메모리 공간을 차지한다.

또한, 하나의 프로그램 안에서 여러 개의 프로세스가 생성되기도 한다.

우리는 하나의 TCP/IP 서버 안에서 여러개의 프로세스를 생성하고자 한다.
--> 다중접속 서버

 

이런 프로세스들은 운영체제로부터 ID를 부여받는다.
이는 프로세스 ID인 PID이며, 2 이상의 정수 형태를 띤다.

+) PID 1 : 운영체제의 실행을 돕는 프로세스이므로 우리가 만드는 것 아님.
++) ps 명령어로 실행 중 프로세스 확인 가능

 


II. 프로세스 생성하기 (fork()함수)

fork()함수는 호출한 프로세스의 복사본을 생성하는 함수이다.

#include <unistd.h>

pid_t fork(void);
    --> 성공시 프로세스ID(PID), 실패 시 -1 반환
    
    fork함수를 호출하면, 반환 값이 구분되는데, 
    
    pid = fork();를 했을 때,
    
    pid == 0 이면, 그것은 자식 프로세스를 움직이고,
    pid != 0 이면, pid는 자식 ID를 가진 값이며, 부모(원본) 프로세스를 움직인다.
    
    아래 설명으로 추가 이해하자.

"호출한 프로세스의 복사본을 생성한다" 라는 말이 이해가 잘 안되었다.

fork함수가 호출된 프로세스를 복사하고, 그 이후 문장을 두 프로세스 모두 실행한다.

전혀 다른 창, 프로그램을 생성하는 것이 아니라
그 코드 흐름내에서 또 다른 프로세스를 조작하는 것이다...

그렇다면 이제 코드블럭에서 설명한 자식, 부모 프로세스를 움직인다는 말이 어느정도 이해가 될 것이다.

부모 프로세스 : fork 함수의 반환 값은 자식 프로세스의 ID
자식 프로세스 : fork 함수의 반환 값은 0                       

코드로 어떻게 활용하는지 보자.

#include <stdio.h>
#include <unistd.h>

int global_val = 0;

int main(){
	pid_t pid;
    
    int local_val = 10;
    
    global_val++; // 1로 증가
    local_val++; // 11로 증가
    
    pid = fork();
    
    // 여기서부터 어떻게 활용하는지 잘 보자.
    
    // 자식 프로세스는 둘다 1씩 빼고 (0,10)
    if ( pid == 0 )
    {
        global_val --;
        local_val --;
    }
    
    // 부모 프로세스는 둘다 1씩 더한다 (2,12)
    else
    {
        global_val ++;
        local_val ++;
    }
    
    if( pid ==0) printf("Child (g,l) Val : (%d,%d)\n",global_val,local_val);
    else printf("Parent (g,l) Val : (%d,%d)\n",global_val,local_val);
    
    return 0;
}

fork()가 호출되기 전 변수는 공유하지만, 호출된 이후는 global, local변수를 모두 따로 다루게 된다.

자식, 부모 각각 (0,10) (2,12) 출력

만약, Depth가 깊어져 자식의 자식의 자식의.....이라면 조금 머리 아플 것 같긴하다ㅠㅠ

+ Recent posts