TCP echo server, client에 대해 봤다. 그럼 이 프로그램의 정상적인 시작과 종료에 대해 알아보자.
처음에 클라이언트가 연결 요청을 하지 않았을 때, 서버는 listen 상태 일 것이다.
netstat -a 명령을 통해 local ip :*, local port : 9877 로 listen 상태인 것을 확인할 수 있다.
그럼 이제 클라이언트 요청에 의해 서버가 연결된 모습을 보자.
보다 시피 연결이 되었을 때는 ESTABLISHED 상태가 되어 있다.
서버의 자식 소켓과 클라이언트 소켓이 ESTABLISHED 상태가 되어 있고, 서버의 부모 소켓은
여전히 Listen 상태가 되어 있다.
그럼 이번에 정상종료 하는 것을 보자.
서버의 자식 소켓의 연결이 끊어지면 부모 소켓으로 SIGCHLD 신호가 전송된다.
기본적으로는 무시하게 되어 있으나, 무시하면 자식이 Zombie state가 되버린다.
소켓으로 치면 계속해서 TIME_WAIT 상태가 되어 있는 것이다.
SIGCHLD 관련하여 시그널 개념에 대해서도 알아보자.
시그널(Signal) 이란
특정 상황이 발생했을 시에 커널이 프로세스에게 보내는 메세지를 의미한다. 소프트웨어 인터럽트 라고도 한다.
그리고 이 시그널에 대한 미리 정의된 작업이 진행되는 것을 시그널 핸들링(Signal handling) 즉, 신호 처리라고 한다.
시그널이 발생할 때마다 항상 시그널 핸들링이 가능하도록 계획되어 있다.
시그널 핸들링은 3가지 방법으로 처리할 수 있다.
1. 시그널이 발생할 때마다 특정 함수를 호출한다.
얘들 특정 함수는 지정된 시그널 번호를 인자로 삼고, 아무것도 반환하지 않는다.
아래와 같이 만들어 놓고 signal 함수로 등록해두면 특정 신호가 나타났을 때 아래 함수가 동작한다.
2. 신호를 무시한다.
SIG_IGN 으로 설정을 하여 시그널을 무시할 수 있따. (다만, SIGKILL 과 SIGSTOP은 무시 못함)
3. 기본 처리 방식을 설정한다.
SIG_DFL로 시그널을 설정하여 default 처리가 가능하도록 한다.
자 이제... 1번, 특정 시그널이 발생했을 때 특정 함수를 호출하도록 만드는 것
=> SIGCHLD를 이용하여 좀비 소켓을 처리하는 함수를 설명하겠다.
위 함수를 signal함수를 이용하여 등록해두는 것이다.
signal(SIGCHLD, sig_chld);
이렇게 말입니다.
SIGCHLD 시그널은 아까 언급했지만, 자식 프로세스가 종료되었을 때 나오는 신호이다.
저렇게 등록해두고 자식 프로세스가 종료된다면 아래와 같이 뜰 것이다.
Solaris % tcpserv02 &
[2] 16936
Solaris % tcpcli01 127.0.0.1
High there
High there
^D
Child 16942 terminated
Accept error: Interrupted system call
클라이언트 측에서 FIN을 전송하여 4HSK통해 정상적으로 자식이 종료된 후에
부모 소켓에게 SIGCHLD 신호가 전달되면서 accept는 블럭킹되어 있다. 다른 접속을 못받는단 말이다.
위에 밑줄친 부분을 보면 에러가 난다.
이렇게 한번 일시 중지된 시스템콜을 커널이 자동으로 재시작 하지 않는다.
저렇게 하면 좀비 프로세스를 제거할 순 있을지라도 멈춘 시스템콜이 다시 실행되지 않아 문제가 된다.
이것을 slow system call 이라고 한다. 영원히 일시 중지 될 수도 있는 시스템콜을 의미한다.
SA_RESTART 라는 플래그가 자동으로 인터럽트된 시스템콜을 재시작하는 OS도 있지만, 근본적인 해결책이 아니다.
그럼 우째야 할까.
시스템콜이 인터럽트 됐을 때 에러가 EINTR (인터럽트) 가 리턴 되는데,
이 EINTR을 핸들링 해주면 이 문제를 해결할 수 있다.
EINTR을 받아도 계속 진행하라는 코드를 추가하면 된다.
이제 인터럽트된 시스템콜 까지 해결했다. 근데 한가지 문제가 더 남아 있다.
wait 함수 때문인데, 종료 시그널 SIGCHLD가 한번에 여러개 오는 경우를 생각해보자.
이것을 wait함수로 처리하면 문제가 있다.
wait 함수는 함수가 호출된 시점에서 종료된 자식 프로세스가 없다면, 임의의 자식 프로세스가 종료될 때까지
블로킹상태에 놓인다. 그래서 waitpid 함수를 이용하여 신호 처리를 구현해야 한다.
'IT 그리고 정보보안 > Knowledge base' 카테고리의 다른 글
정보보호 관리 (0) | 2021.04.12 |
---|---|
입출력 다중화 (I/O Multiplexing) (0) | 2021.04.11 |
TCP echo Server/Client (1) | 2021.04.11 |
소켓 프로그래밍 (0) | 2021.04.11 |
네트워크 소켓(Socket)은 무엇인가 (0) | 2021.04.11 |