티스토리 뷰

2.5 소켓 관련 UNIX 시스템 콜

2.5.1 signal()

▶ 유닉스 시스템에서 어떤 이벤트(event)가 발생하면 이것을 프로세스 사이에

알리는 수단으로 시그널이 사용된다.

표 2-3 소켓 관련 시그널 종류

SIGINT

인트럽트 키(Ctrl+C) 입력시 발생

SIGFPE

부동 소수점 연산 에러를 나타냄

SIGIO

I/O가 가능한 상태를 나타냄.

SIGURG

Out-of-band 데이터 도착과 같은 긴급한(urgent) 소켓 상태를 나타냄.

▶ 시그널이 발생하였을 때 유닉스 커널이 제공하는 디폴트 처리 내용 대신 다른

동작을 수행하도록 하려면 signal() 시스템 콜을 사용한다. 아래에서 signal

(SIGIO, sigio_func) 호출 후 SIGIO 시그널이 발생하면 sigio_func() 함수가 수행

된다.

      #include <signal.h>
      int sigio_func();               /* 사용자 정의 함수 선언 */
      main() {
      signal(SIGIO, sigio_func); /* 시그널 처리 함수 지정 */
      :
      }

        int sigio_func() {
        /* SIGIO 시그널 발생시 처리 내용 */
        }

▶ 어떤 시그널이 발생하였을 때 이를 단순히 무시하려면 다음과 같이 무시할 시

그널의 종류(예를 들면 SIGIO)를 지정하고 옵션으로 시그널 무시(SIG_IGN)를 선

택한다.

      signal(SIGIO, SIG_IGN);

■ signal_test.c

      카운터 프로그램이 실행되는 도중에 사용자가 Ctrl-C를 입력하면 시그널 SIGINT

      가 발생하는데, 이 때 프로그램이 종료되는 것이 아니라 my_signal()이라는 함수가

      호출된다.

      실행예

        > signal_test
        0
        1
        ^C
        Ctrl-C pressed.
        2
        3
        ^C
        Ctrl-C pressed.
        4
        ^C
        Ctrl-C pressed.
        >

      프로그램 리스트

      /*---------------------------------------
      파일명 : signal_test.c
      기 능 : signal() 시스템 콜 사용 예
      컴파일 : cc -o signal_test signal_test.c
      사용법 : signal_test
      ----------------------------------------*/
      #include <sys/types.h>
      #include <signal.h>
      #include <stdio.h>
      #include <unistd.h>
      int my_signal();    /* 새로운 시그널 처리 함수 선언 */
      int count = 0;       /* Ctrl-C 입력 횟수 카운터 */

      int main() {
      int i = 0;
      if(signal(SIGINT, my_signal) == SIG_ERR) {

      printf("singal() error\n");
      exit(0);
      }
      while(count < 3) {
      sleep(1);      /* 1초간 기다림 */
      printf("%d\n", i++);
      }
      }
      /* end of main  */

      /* 시그널 처리 함수 정의 */
      int my_signal() {
      printf("\nCtrl-C pressed.\n");
      count++;

      signal(SIGINT, my_signal);  /* signal()을 다시 호출함 */

      return 0;
      }

2.5.2 fork()

유닉스에서 프로세스는 fork()를 이용해서 자신과 똑같은 기능을 수행

하는 프로세스를 하나 복제할 수 있다.

두 프로세스는 프로그램 코드, 스택, 파일기술자, 소켓번호 등은 공유하나, 변

수들은 공유하지 않는다.

▶ fork()가 불리면 그 순간에 하나의 프로세스가 두 개의 프로세스로 되는데, 두

프로세스는 수행할 일을 구분하기 위하여 두 프로세스의 fork() 리턴문이 서로 다

르다는 것을 이용한다.

▶ 새로 생긴 자식 프로세스의 ID 번호(PID: Process Identification)는 부모 프로

세스의 PID와 구별된다.

▶ 부모 프로세스에게는 fork()의 리턴값으로 새로 생성된 자식 프로세스

의 PID가 리턴되며 자식 프로세스의 fork()의 리턴값은 0이 된다.

그림 2-14 fork()의 수행과정

▶ 프로세스의 작업 구분 예

        int  PID;
        PID = fork();
        if(PID == 0) {

        child_work(); /* 자식 프로세스용 코드 */
        } else {
        parent_work();/* 부모 프로세스용 코드 */
        }

■ fork_test.c

      부모와 자식 프로세스가 같은 이름의 변수를 각각 증가시키고 그 결과를 확인한

      다.

프로그램 리스트

/* ----------------------------------------------------
파일명 : fork_test.c
기 능 : fork() 시스템 콜 사용 예
컴파일 : cc -o fork_test fork_test.c
사용법 : fork_test
-----------------------------------------------------*/
#include <sys/types.h>
#include <unistd.h>
int global_var = 0;      /* 전역 변수 선언 */

int main(void) {
pid_t pid;
int    local_var = 0;     /* 지역 변수 선언 */
if((pid = fork()) < 0) {
printf("fork error\n");
exit(0);

/* 자식 프로세스 */
} else if (pid == 0) {
global_var++;
local_var++;
printf("CHILD - my pid is %d and parent's pid is %d\n", getpid(), getppid());
} else {

/* 부모 프로세스 */
sleep(2);/* 2초 쉰다 */
global_var += 5;
local_var += 5;
printf("PARENT - my pid is %d, child's pid is %d\n", getpid(), pid);
}
printf("\t global var : %d\n", global_var);
printf("\t local var : %d\n", local_var);
}

    실행예
    > fork_test
    CHILD - my pid is 12557 and parent's pid is 12556
    global var : 1
    local var : 1
    PARENT - my pid is 12556 and child's pid is 12557
    global var : 5
    local var : 5

    ▶ 여기서 부모 프로세스가 global_var과 local_var을 각각 5씩 증가시켰

    는데 6이 되지 않고 5가 되었다는 사실에 주목하자!! (파일이나 소켓은 공

    유하지만 변수는 공유하지 않는다)

    참조) http://cafe.naver.com/segame.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=94