임베디드 리눅스

네트워크 프로그래밍 - 다중 접속 서버 기초 이론 ( feat. 시그널 핸들링 )

개발자_WH 2022. 2. 14. 14:49
728x90
반응형

이제 아마도 이론 2 번 정도? 정리한 후에

코딩을 해볼꺼에요. 이 과정이 조금 지루하긴 하지만 화이팅 합시다

저번 글에서는 좀비 프로세스, fork, waitpid 등에 대해 다뤘어요

기억이 나질 않는다면 아래 글을 참조해 주세요

 

2022.02.14 - [임베디드 리눅스] - 네트워크 프로그래밍 - 다중 접속 서버 구현을 위한 기초 (feat. 프로세스, fork(), 좀비 프로세스 )

 

네트워크 프로그래밍 - 다중 접속 서버 구현을 위한 기초 (feat. 프로세스, fork(), 좀비 프로세스 )

안녕하세. WH 입니다. 피곤한 월요일이네요. 저만 그럴까요? ㅎㅎ 그건 그거고 여튼 시작해 보겠습니다. 네트워크 프로그래밍이 반응이 좋아서 다중 접속 서버 구현을 한번 해볼까합니다. 대표적

developer-wh.tistory.com

 

시그널 핸들링

  이게 뭐냐면? 결국에 wait나 waitpid 나 자식 프로세스가 종료되기까지 기다리는 함수잖아요. 근데 부모 프로세스는 그것 말고도 할 일이 많단 말이죠? 결국 할 일을 어떻게 분배할거냐에 대한 내용이에요.

 

  자식 프로세스는 저번 글에 의하면 누가 종료하죠? 운영체제가 부모한테 값을 전달하며 종료하죠? 그러니까 주체는 운영체제에요. 그럼 운영체제는 부모 프로세스가 일하고 있을 때, 자식이 종료되었다는 사실을 알려주면, 부모는 하던 일을 잠시 멈추고 자식 프로세스 종료에 관한 일을 처리하면 되겠네요. 이렇게 운영체제가 어떤 상황이 발생 했음을 시스템에게 알리기 위한 메세지가 바로 시그널이에요. 그리고 그 메세지와 관련해서 미리 정해진 작업을 진행하는 것을 핸들링 이라고 해요. 즉 운영체제와 프로세스는 이런 대화를 하겠죠?

 

프로세스 : 자식이 종료되면 zombie_handler 함수 호출 좀... 그 안에 호출 시 규칙은 그 함수 안에 정해 놓음

운영체제 : 오키. 종료되면 내가 대신 zombie_handler 호출해 줌.

프로세스 :  ㅇㅇ ㅅㄱ

 

  즉, 프로세스가 자식 프로세스의 종료라는 상황 발생시 특정 함수의 호출을 운영체제에게 요구하는 것이 시그널 등록이며, 시그널 등록은 아래의 함수의 호출을 통해 이루어집니다.

#include <signal.h>

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

 

반응형

- 함수이름 : signal

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

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

 

 이렇게 되어 있는데요. signo 인자에는 특정 상황에 대한 정보가, void (*func)(int) 에는 특정 상황에서 호출될 함수의 주소 값을 전달합니다. 그럼 signo 에 의해 명시된 상황 발생 시에 void(*func)(int) 로 전달된 주소 값의 함소가 호출 되겠죠. 그 특정 상황과 그 상황을 설명하는 상수를 정리해 볼까요?

 

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

  - SIGINT     : CTRL + C 가 입력된 상황

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

 

  우리가 해야할 일은 signal( 시그널, 함수 ); 라는 호출에서 함수에 대한 선언 하고 동작을 정의하는 일이랍니다. 그런데 signal 함수는 약간 트렌디하지 못한 함수에요. 대신 sigaction 이라는 함수가 사용되죠. 그럼 처음부터 알려주면 되잖아요. 어떻게 합니까. 쓰다보니 생각난걸.. ㅎㅎ

 

sigaction 구조체를 먼저 살펴보겠습니다.

struct sigaction
{
    void(*sa_handler)(int);
    sigset_t sa_mask;
    int sa_flags;
}

sa_mask, sa_flags는 모두 0으로 초기화 하고, sa_handler 에는 handler 함수의 주소 값을 지정하면 됩니다. 왜 0으로 초기화해요? 좀비 프로세스 생성을 막기만 하면되니까 자세한 설명은 넘어갈게요.

 

#include <signal.h>
/*성공 시 0, 실패 시 -1*/
int sigaction(int signo, const struct sigaction * act, struct sigaction * oldact);

- signo :  시그널의 정보를 인자로 전달
- act : 첫번째 인자로 전달된 상수에 해당하는 시그널 발생 시 호출될 함수의 정보 전달
- oldact : 이전에 등록되었던 시그널 핸들러의 함수 포인터를 얻는데 사용되는 인자, 필요없다면 0 전달

 

우리가 할 일이 뭐겠어요?

 

  0. sig_handler 선언 및 정의  

  1. 구조체 초기화

  2. sigaction 함수 호출 

이 정도되겠네요. 와 드디어! 기초 이론이 끝나가는 것 같아요. 이제 마지막으로 다중 접속 서버의 경우 어떤 상황으로 구현되어야 하는지를 알아보고, 코드로 구현해 봅시다. 이상 WH 였습니다.

728x90
반응형