서론
minitalk 과제는 SIGUSR1, SIGUSR2를 사용해서 클라이언트 프로그램에서 서버 프로그램으로 메시지를 보내고 서버 프로그램은 해당 메시지를 출력하는 프로그램을 작성하는 과제이다. 이 과제에서는 pid 값, signal 및 kill 함수 등에 대해 배우게 된다.
개념
pid
프로세스 id이다. 쉘에서 ps 명령을 통해서 pid를 확인할 수 있으며 getpid() 함수를 사용해서 자신의 pid 값을 가져올 수도 있다.
kill 함수
#include <signal.h>
int kill(pid_t pid, int sig);
pid에 해당하는 프로세스(또는 그룹)로 sig에 해당하는 값을 보낸다.
https://www.ibm.com/docs/hr/zos/2.4.0?topic=functions-kill-send-signal-process
signal 함수
#include <signal.h>
void ( *signal (int sig, void(*func)(int)) )(int);
함수 호출 이후 signal 값을 받으면 func을 실행시킨다(제어를 넘긴다). 이 함수를 통해 client 프로그램에서 보낸 시그널을 받을 수 있다. 또한 이 함수는 나중에 minishell 과제를 할 때에도 사용하게 되니 미리 알아두자. cntl+c cntl+\ 등 키보드 입력을 통해서도 시그널을 보낼 수 있다.
https://www.ibm.com/docs/ko/i/7.3?topic=functions-signal-handle-interrupt-signals
구현
client.c
우리는 SIGUSR1, SIGUSR2 두 개의 시그널만 사용할 수 있으므로 입력받은 메시지를 보내기 위해 char 형태를 이진수로 바꾸고 그에 해당하는 시그널을 보내면 된다. 예를 들어 'A'의 아스키코드 값은 65이고 이를 이진수로 나타내면 1000001이다. 여기에 char 형은 1바이트 = 8비트를 저장 공간으로 사용하므로 모든 char 값을 보낼 수 있으며 서버가 signal 8번마다 시그널을 char 형으로 치환할 수 있도록 하기 위해서 8자리를 채워서 이진수 값으로 보내면 된다. A는 '01000001' 이런 식으로 8자리를 맞추면 된다. 나는 SIGUSR1 = 0, SIGUSR2 = 1로 치환하였다.
2진수로 바꾼 숫자를 낮은 자리부터 차례대로 보냈다. 높은 자리부터 차례대로 보내는 방법도 존재한다. usleep(50)은 클라이언트에서 보내는 속도와 서버가 받는 속도의 차이 때문에 신호가 유실될 때도 있어서 사용하였다.
server.c
클라이언트에서 낮은 자리 순서로 시그널을 보냈으니 서버에서는 이에 맞추어 8개의 신호씩 끊어서 char 형을 만들면 된다.
handler 함수는 signal 함수에서 호출된다.
signal(SIGUSR1, handler);
signal(SIGUSR2, handler);
Makefile
이전까지의 과제와는 다르게 최상위 디렉터리에서 모든 코드를 컴파일할 수 있는 Makefile을 작성해야 한다. 위와 같이 하위 디렉터리를 지정해 준 후 for 문을 사용해서 하위 디렉터리 하위 디렉터리의 make 명령까지 실행해 주었다.
후기
평가를 받으며 개선하면 좋을 것 같다는 부분이 있었다. server 프로그램에서 8개의 신호를 받을 때마다 한 문자를 출력하는데 이렇게 한 문자씩 출력하면 system call을 많이 해서 코스트가 발생한다는 내용이었다. 다시 구현한다면 이 부분도 참고해서 구현해야겠다.
'대외활동 > 42서울' 카테고리의 다른 글
[42서울] Netpractice LEVEL 8 문제 풀이 (1) | 2024.11.11 |
---|---|
[42서울] minishell 테스트 케이스 (0) | 2024.08.11 |
[42서울] so_long 그래픽, mlx 라이브러리 (0) | 2024.08.11 |
[42서울] so_long 맵 유효성 검사(BFS) (0) | 2024.07.22 |
[42서울] get_next_line 구현 (메모리 누수 잡기, 구현 tip) (1) | 2024.07.21 |