이제부터 클라이언트로부터 송신받은 시그널을 서버가 잘 수신했는지 확인하는 체커를 구현할 것이다.
체커 시스템을 구현하기 전 클라이언트는 서버가 잘 수신했는지 알 수 있는 방법이 없다. 그저 시그널을 송신할 뿐 서버가 수신했는지의 여부는 따질 수 없다. 네트워크로 따지자면 udp와 비슷한 것 같다.
이렇듯 클라이언트가 서버가 잘 수신했는지 알기 위해 체커 시스템을 구현해 보겠다.
구현 아이디어는 이렇다.
서버가 클라이언트로부터 8bit를 수신받으면 수신받은 프로세스로(클라이언트로) 시그널을 하나 보내는 것이다. 이렇게 하면 클라이언트는 main에서 인자로 받은 argv[2]와 서버로부터 받은 시그널의 개수를 비교해 보면 서버로 시그널이 잘 갔는지 확인할 수 있는 것이다.
따라서 클라이언트에 SIGUSR1과 SIGUSR2를 handle할 수 있는 핸들러를 구현하고, 이 핸들러에서 받은 시그널을 count하면 된다. 클라이언트의 메인 부분에서는 이 count와 argv[2]의 길이와 비교해서, 같다면 message received를, 다르다면 received error를 출력하면 된다.
실제로 바꾼 부분은 다음과 같다.
클라이언트에서는 기존에 SIGUSR1과 SIGUSR2를 다루는 핸들러가 이미 있으므로 그 핸들러에 count해주는 부분만 추가하면 된다. handler에서 count를 하되, 이를 main에서 사용하니 이 count 변수는 전역으로 둔다.
그 뒤 클라이언트의 main에서 count와 argv[2]의 길이를 비교해, 같으면 잘 받았다고 출력하고 다르면 에러라고 출력한다.
<바꾼 부분>
size_t g_charnum = 0;//count함수 추가
...
size_t ft_strlen(const char *str)
{
size_t index;
index = 0;
while (str[index] != '\\0')
{
index++;
}
return (index);
}
...
void clienthandler(int signum, siginfo_t *siginfo, void *context)
{
(void)signum;
(void)siginfo;
(void)context;
g_charnum++;
}
int main(int argc, char **argv)
{
struct sigaction catch;
g_charnum = 0;
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]);
usleep(100);
if (charnum != ft_strlen(argv[2]))
{
write(1, "receive error\\n", 15);
return (1);
}
else
{
write(1, "message received\\n", 18);
}
//argv[1]에는 pid, argv[2]에는 보낼 문자열 있음. 서버가 pid를 출력하면 이를 긁어서 클라이언트가 pid 뒤에 문자열 보내서 서버로 뜨게 함
}
return (1);
}
서버에서는 8bit를 수신하였을 때 원래는 출력만 하고 말았지만, 이제는 수신받은 프로세스로 시그널을 하나 보내준다. 클라이언트에서 SIGUSR1과 SIGUSR2 모두를 핸들하고 있기 때문에 SIGUSR1이나 SIGUSR2의 아무 시그널이나 송신해도 된다.
송신 실패했을 경우에는 exit으로 프로세스를 종료시킨다.
binaryToDecimal에서 8bit 수신 시 시그널을 하나 보내준 것과 binaryToDecimal로 수신한 시그널을 보낸 프로세스의 pid를 보내 준 것만 다르다.
<바꾼 부분>
void serverhandler(int signum, siginfo_t *siginfo, void *context)
{
(void)siginfo;
(void)context;
binaryToDecimal(signum == SIGUSR2, siginfo->si_pid);//보낸 프로세스의 pid도 전달
}
void binaryToDecimal(int binary, int pid)
{
static unsigned char ch = 0;
static int index = 7;
ch += (binary << index--);
if (index < 0)
{
write(1, &ch, 1);
index = 7;
ch = 0;
if (kill(pid, SIGUSR1) == -1)
{
exit(0);
}
usleep(100);
}
}