client에서는 server를 시작할 때 출력된 서버의 pid를 이용해 argv[2]에 입력된 문자열을 서버에 sigusr1과 sigusr2의 시그널을 보냄으로써 전송한다.
./server 명령어를 통해 서버를 실행하면

위와 같이 서버 프로세스의 pid가 나온다. 이를 이용해 클라이언트는 서버로 시그널을 보낼 수 있다.
우리는 클라이언트에서 전달하고자 하는 문자열을 서버로 전송해야 한다. 이 때 사용자 정의 시그널인 SIGUSR1과 SIGUSR2를 이용할 수 있다.
우리는 시그널을 다룰 시그널 핸들러를 사용해야 하는데, 자동적으로 정의된 default 핸들러를 사용해도 되고, 문자를 받았다고 표시하는 사용자 정의 핸들러를 사용할 수도 있다.
void clienthandler(int signum, siginfo_t *siginfo, void *context)
{
(void)signum;
(void)siginfo;
(void)context;
g_charnum++;
}
클라이언트에서는 전역으로 선언된 g_charnum을 1 더해주는 핸들러를 사용한다. 이는 SIGUSR1과 SIGUSR2 시그널이 클라이언트로 왔을 때 시그널을 다룰 핸들러로 사용되는 것인데, 이는 보너스를 위해 구현한 것이다. 보너스를 굳이 하지 않을 것이라면 안해도 된다.
이를 응용해서 서버에서 8개의 signal이 받아지면(한 문자가 출력되면), 서버에서 클라이언트로 시그널을 하나 줘서 클라이언트에서 받은 시그널의 개수와 argv[2]로 받은 문자열의 문자 수와 같은지 비교해서 체커 시스템을 구현할 수도 있겠다.
이를 위해 먼저 핸들러를 시그널에 등록하자. signal()을 쓸 수도 있겠지만 sigaction 구조체를 이용해서 구현하자.
int main(int argc, char **argv)
{
struct sigaction catch;
catch.sa_flags = SA_SIGINFO;
catch.sa_sigaction = clienthandler;//핸들러를 내 핸들러로 지정
if (sigaction(SIGUSR1, &catch, NULL) == -1)//SIGUSR1이 들어왔을 때 handler로 처리
{
exit (1);
}
if (sigaction(SIGUSR2, &catch, NULL) == -1)//SIGUSR2가 들어왔을 때 handler로 처리 sigaction(signum, act, oldact);
{
exit (1);
}
if (argc != 3)//인자 3개 아닐 때
{
printf("invalid arguement number\\n");
exit (1);
}
else
{
send_message(atoi(argv[1]), argv[2]);
//argv[1]에는 pid, argv[2]에는 보낼 문자열 있음. 서버가 pid를 출력하면 이를 긁어서 클라이언트가 pid 뒤에 문자열 보내서 서버로 뜨게 함
}
return (1);
}
catch라는 sigaction 구조체가 있고, 이 구조체에 sa_flags를 SA_SIGINFO로 선언한다. signal()만 써도 되겠지만 서버에서 siginfo 구조체를 쓰기에 통일성을 주기 위해 siginfo로 선언한다.
siginfo로 flag가 선언되면 catch.handler 대신 catch.sa_sigaction에 핸들러를 등록한다. siginfo 구조체를 사용하려면 sa_sigaction에 핸들러를 등록해야 하기 때문이다. 더 자세한 내용은 아래에 있다.
sigaction 함수로 SIGUSR1과 SIGUSR2에 siginfo와 핸들러 정보가 담겨 있는 sigaction 구조체를 등록한다. 이 구조체에 정의되어 있는 act로 행동할 것이다. 뒤의 NULL은 old act인데, 신경쓰지 않아도 된다.
sigaction 함수의 리턴값은 등록에 성공했으면 0, 실패했으면 -1을 반환한다. 따라서 -1이 반환되면 프로그램을 종료시킨다.