- tcp socket을 이용
- fork로 프로세스 생성 (여러 client와 동시에 통신하기 위해서)
- client 쪽에서 fin을 보내는 구조
- backlog queue size == 5
- 서버는 while-loop으로 accept을 계속해서 수행
- signal handling으로 zombie process reap
client : serv_sock (1개) server : serv_sock(listening, 1개), clnt_sock(read write, 1개)
- 여러 client와 통신을 위해 fork를 하면, server의 clnt_sock 하나씩 생성.
- 부모와자식 프로세스에서 모두 close 해주어야 fin이 정상적으로 수행
- server 먼저 켜놓기 ex) ./server 9190
- client로 접속 ex) ./client 127.0.0.1 9190
- client가 메세지를 보내면 서버는 그대로 반사해서 보내줌
- client에서 q or Q을 누르면 close -> fin
- server는 여러 client를 동시에 수용 가능 (n:1)
- client's process : 1개
- server's parent process : while-loop 수행하며 accept + clnt_sock close
- server's child process : echo 수행 + serv_sock close
- client가 connect(syn)을 하면, server는 accept 및 fork로 child process 생성
- server's child process : file descriptor 복사로 인해 listening socket 미리 종료 // server's serv_sock close -1
- server's parent process : server's clnt_sock close -1 // 복제 되기 때문에 종료해주기
- server's child process는 복제된 serv_sock file descriptor를 close
- server's child process는 echo 역할 수행
- client's process : close : q or Q 를 쳐서 종료요청 수행 // client's serv_sock close
- server's child process : server는 read에 0이 들어오는 것을 보고, fin을 detect 후, server's clnt_sock close -2, 그리고 자식 프로세스 종료
- server's child process 종료 시키면 singal handler called
- singal handler : zombie process 생성을 막기 위해 waitpid로 reap
- server는 while-loop 을 통해 계속해서 client의 요청을 accept (block 함수)
ps al 커맨드로 확인해보면 multi-process server에서 reaping 해주지 않는다면 zombie process가 남게 되는 것을 볼 수 있다.
자식 프로세스가 종료되면, 부모 프로세스는 wait or waitpid 같은 함수로 자식을 reaping을 해주어야 한다. 아니면 좀비 프로세스가 계속 쌓이게 된다. 물론 서버가 down되면 zombie 프로세스는 메모리에서 해제되지만, 실제 서버는 수 많은 client를 상대로 계속해서 돌아가야만 한다. 따라서 zombie process가 메모리 낭비를 하지 않도록 reaping 해주는 것은 꼭 필요하다.
실제 3개의 client를 동시에 접속시킨 후 할당된 tcp port들.
server -> 1 : listening socket n : clnt_sock(이 소켓으로 client와 통신한다.) client -> n : 단일 프로세스로 서버에게 접속한다. n명이면 n개.
요즘은 multi-thread 환경의 서버가 대부분이지만, multi-process 환경에서 서버가 많은 client를 수용하는 과정을 생각해 보게 되었다. 서버의 특성 상 24시간 내내 돌아가야 하며, zombie process 같은 메모리 누수 관리를 잘 해주어야 한다고 생각했다.
