본문 바로가기

공부/tcp/ip 프로그래밍

10장 멀티프로세스 기반의 서버구현

반응형

프로세스 =

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

 

프로세스는 프로세스간에 코드영역, 데이터 영역, 힙 영역, 스택 영역을 공유하지 않고 각자 가지고 있음

 

코드영역: 프로그램의 실제 코드가 저장되어 있는 영역

스택영역 : 로컬변수, 함수에 호출에 관련된 정보, 임시데이터가 저장되는 영역

영역 : 동적 메모리 할당에 사용되는 영역

데이터영역 : 전역변수등의 데이터가 저장되는 영역

 

프로세스(자세히) =   

OS는 가상메모리를 이용하여 프로그램을 관리

 

%참고

c언어 상에서 사용하는 메모리는 가상메모리(register + cach + 램 + 하드디스크)

 

다중접속 서버의 구현방법들

멀티프로세스 기반 서버 = 다수의 프로세스를 생성하는 방식으로 서비스 제공

멀티플렉싱 기반 서버 = 입출력 대상을 묶어서 관리하는 방식으로 서비스 제공

멀티쓰레딩 기반 서버 = 클라이언트의 수만큼 쓰레드를 생성하는 방식으로 서비스 제공

 

프로세스 ID = 모든 프로세스는 생성되는 행테에 상관없이 운영체제로부터 ID를 부여 받음

 

호출한 프로세스의 복사본을 생성(메모리 영역까지 동일하게 복사)

#include <unistd.h>

pid_t fork(void);

성공시 프로세스 id, 실패시 -1반환

 

부모 프로세스

fork함수의 반환 값은 자식 프로세스의 id

자식 프로세스

fork함수의 반환 값은 0

 

좀비 프로세스

좀비프로세스.pptx

 

 

생성 이유 :

자식 프로세스는 실행이 끝나고 반환 값을 운영체제에 전달됨

운영체제는 이 값이 자식 프로세스를 생성한 부모 프로세스에게 전달될 때까지 자식 프로세스를 소멸시키지 않음(=좀비 프로세스)

부모프로세스는 운영체제에게 반환 값을 달라는 함수를 호출하면 반환 값이 부모프로세스에게 전달되고 자식 프로세스는 소멸

 

좀비 프로세스의 소멸1

#include <sys/wait.h>

pid_t wait(int* statloc);

성공시 종료된 자식 프로세스의 ID, 실패시 -1 반환

종료된 자식 프로세스가 없다면, 임의의 자식 프로세스가 종료될 때까지 블로킹 상태에 놓임

 

WIFEXITED(status) 자식 프로세스가 정상 종료한 경우 참(true)을 반환

WEXITSTATUS(status) 자식 프로세스의 전달 값을 반환

 

좀비 프로세스의 소멸2

#include <sys/wait.h>

pid_t waitpid(pid_t pid, int* statloc, int options);

성공시 종료된 자식 프로세스의 ID(or 0), 실패시 -1 반환

 

pid : 종료를 확인하고자 하는 자식 프로세스의 ID 전달, 이를 대신해서 -1을 전달하면 wait 함수와 마찬가지로 임의의 자식 프로세스가 종료되기를 기다림

statloc : wait함수의 매개변수 statloc과 동일한 의미로 사용

options 헤더파일 sys/wait.h에 선언된 상수 WNOHANG을 인자로 전달하면, 종료된 자식 프로세스가 존재하지 않아도 블로킹 상테에 있지않고, 0을 반한하면서 함수를 빠져 나옴

 

시그널함수

#include <signal.h>

void (*signal(int signo, void (*func)(int)))(int);

// = void (*) (int) signal(int signo, void (*func)(int))

      ------------ --------------------------------

           반환값                  함수이름(매개변수)

시그널 발생시 호출되도록 이전에 등록된 함수의 포인터 반환

반환 형 : void(*)(int) <= 함수포인터

 

함수이름 : signal

매개변수 선언 : int signo, void(*func)(int)

반환형 : 매개변수형이 int이고 반환형이 void인 함수 포인터

 

참조 : http://kin.naver.com/qna/detail.nhn?d1id=1&dirId=1040101&docId=72100571&qb=dm9pZCAoKnNpZ25hbA==&enc=utf8&section=kin&rank=1&search_sort=0&spq=1&pid=RT5d5U5Y7vVssufCQHZsssssssd-088844&sid=UWJQJXJvLDsAACSkdpM

 

signal 함수를 통해서 등록 가능한 특정 상황과 그 상황에 할당된 상수

SIGALRM : alarm 함수호출을 통해서 등록된 시간이 된 상황

SIGINT     : ctrl+c가 입력된 상황

SIGCHLD : 자식 프로세스가 종료된 상황

 

alarm 함수

#include <uistd.h>

unsigned int alarm(unsigned int seconds);

0 또는 sigalrm시그널이 발생하기까지 남아있는 시간을 초 단위로 반환

 

sigaction 함수

#include <signal.h>

int sigaction(int signo, const struct sigaction* act, struct sigaction* oldact);

성공시 0, 실패시 -1 반환

 

signo : signal 함수와 마찬가지로 시그널의 정보를 인자로 전달

act : 첫 번째 인자로 전달된 상수에 해당하는 시그널 발생시 호출될 함수(시그널 핸들러)의 정보 전달

oldact : 이전에 등록되었던 시그널 핸들러의 함수 포인터를 얻는데 사용되는 인자, 필요 없다면 0 전달

 

struct sigaction

{

void (*sa_handler)(int);

sigset_t sa_mask;

int sa_flags;

}

 

멀티태스킹 서버.pptx

 

 

 

 

시그널함수 설명

만약 다음과 같은 함수가 있다고 합시다...

 

void func(int a);

 

이러면 함수이름은 func 이고 패러미터는 int a 이고 리턴은 void 이지요

그러면 이 함수를 가리키는 포인터는 어떻게 쓸까요?

 

void (*p)(int a); 

 

이렇게 씁니다. 즉, 포인터 p 가 함수를 가리키는 것이고 그 함수의 패러미터가 int a 인것이지요

이때 함수포인터가 지시하는 함수의 패러미터는 이름을 생략해도 됩니다.

물론 함수 선언할 때 생략해도 되기 때문에 이것이 허용되는 것이지요...

 

고로...

 

void (*p)(int);

 

이렇게만 해도 됩니다.

님께서 헷갈리시는 것이 바로 이름도 없이 int만 (int)로 나오니까 혼동하신 듯 하시네요

 

또 signal 함수의  프로토타입 설명을 요구하셔서 아래에 적어 보았습니다.

 

void (*signal(int signum, void (*handler)(int)))(int);

 

위의 함수 프로토타입을 이해해 봅시다

그러기 위하여 위의 함수를 분해해 보겠습니다.

 

먼저 signal이라는 이름부터 봅시다.

 

signal은 바로뒤의 괄호로 보아 함수이름이 됩니다.

(위의 문장에서 적색 부분)

 

즉, signal(   ) 이 기본적인 모양이지요...

 

함수는 어떤것들을 지정합니까?

함수가 받는 parameter와 리턴 타입을 지정해 줘야 합니다.

당연히 parameter는 괄호안에 적지요...

 

그럼 이 함수의 parameter는 뭘까요?

parameter까지 적어봅시다. (보라색 부분)

 

signal(int signum, void (*handler)(int))

 

분석해 보면 이 함수는 parameter가 두개인 것을 알수 있습니다.

signum과 handler 가 그것입니다.

 

signnum은 int 타입입니다.

그럼 handler는 타입이 뭘까요?

 

handler 관련 부분만 추려볼까요?

 

void (*handler)(int)

 

이렇게 됩니다. 이게 뭔가요? 함수포인터입니다.

즉, handler는 함수포인터로서 위에서 이름빼고 보면 void (*)(int) 가 됩니다.

즉, int를 받고 리턴이 void인 함수의 포인터입니다.

 

자, 그럼 signal 함수의 패러미터는 이해되셨는지요?

 

그럼 이번에는 signal 함수의 리턴을 볼까요?

 

void (*signal(int signum, void (*handler)(int)))(int);

 

여기서 ( ) 안의 것은 패러미터이니까 제외하고 보면

 

void (*signal(...))(int);

 

이렇게 됩니다. 자 그럼 이게 뭘까요?

위에서 빨간부분은 signal 함수이므로 이것을 빼고 보면 나머지가 바로

signal 함수의 리턴타입이 되는 겁니다.

 

즉, void (*)(int) 아니겠습니까?

 

이것이 signal 함수의 리턴입니다. 결국 하까 본 handler 함수와 동일한 모양이지요

int를 받고 리턴이 void인 함수의 포인터 입니다.

 

님께서 질문하신 (int)는 결국 signal 함수의 리턴인 함수포인터가 가리키는 함수의

패러미터 타입인 것입니다.

 

그럼 전체적인 해석이 되셨는지요?

 

void (*signal(int signum, void (*handler)(int)))(int);

 

위에서 보시면 적색은 signal 함수 표시이고

보라색은 이 함수의 패러미터를 보이고 있는것입니다. (signum과 handler)

그리고 파란색은 리턴 타입을 보이고 있습니다. void (*)(int)

 

추가로 말씀드리면 signal 함수의 두번째 패러미터인 handler 의 타입과

이 signal 함수의 리턴타입은 둘 다 void (*)(int)로 일치 합니다.

반응형