클라이언트가 서버로 문자열을 전송하면 서버에서 해당 문자열을 출력하도록 하는 프로그램을 만들어보는 프로젝트
UNIX의 signal을 활용하여 제작
- 서버가 실행되면 서버의 pid(getpid())를 출력하고 signal(signal())함수를 사용해 시그널을 받기위해 대기(pause())
- 클라이언트 실행시 서버의 pid와 보낼 메시지를 받으며 시작
- 클라이언트는 보낼 메시지의 문자 하나하나의 아스키코드값을 2진수로 변환
- 변환한 2진수값 하나하나를 kill(kill())함수를 사용해 서버로 시그널을 전송
- SIGUSR1시그널은 2진수의 0, SIGUSR2시그널은 1로 간주하여 일정 시간텀을 두고 서버로 전송
- 서버는 수신한 시그널을 8번(1byte = 8bit)마다 끊어 2진수로 받은 뒤 10진수로 변환하여 문자의 아스키코드를 바탕으로 출력
main함수
- getpid() 함수를 사용해 현재 프로세스의 id를 가져온 뒤 pid를 출력해줌.
이후 signal함수를 사용해 SIGUSR1, SIGUSR2 시그널을 수신했을때 어떤 함수를 호출할지 등록함.
pause함수는 시그널이 들어올때까지 프로세스를 종료하지않고 대기상태로 유지해주기때문에 while(1)을 사용해 무한 루프를 돌게하여 지속적으로 시그널을 수신할 수 있도록 해줌int main(void) { set_data(getpid()); //메시지를 받는데 사용할 저장공간들을 초기화 if (g_data.pid == 0) return (0); write(1, "pid : ", 6); write(1, g_data.pid, strlen(g_data.pid)); // 서버의 pid를 출력 write(1, "\n", 1); free(g_data.pid); signal(SIGUSR1, sig_usr1); // SIGUSR1시그널 수신시 sig_usr1 실행 signal(SIGUSR2, sig_usr2); // SIGUSR2시그널 수신시 sig_usr2 실행 while (1) pause(); // 프로세스가 종료되지않도록 멈춰줌 return (0); }
sig_usr1 함수
- 클라이언트로부터 SIGUSR1 시그널을 받았을때에 실행
클라이언트로부터 받은 시그널을 0 으로 생각하고 문자를 이루는 8개의 비트중 현재 카운트에 해당하는 자리에 0을 넣어줌.
이후 카운트를 1 증가시키는데 이떄 카운트가 8 이라면 1바이트가 완성된것이므로 문자를 출력하고 카운트를 초기화시켜줌
또한 문자가 '\0'이라면 문자열을 모두 받은것이기에 개행을 출력해줌void sig_usr1(int signum) // SIGUSR1 시그널을 0에 대응 { char a; (void)signum; g_data.bit[g_data.count] = '0'; //실행시 문자 2진수의 현재 자릿수를 0으로 생각하고 넣어줌 g_data.count++; // 자릿수를 증가 if (g_data.count == 8) //8 비트를 가득 채울시 { g_data.dec = change_dec(g_data.bit); // 10진수로 변환해줌 a = (char)g_data.dec; if (a == '\0') // 문자라 \0이라면 문자의 끝이므로 줄바꿈 출력 write(1, "\n", 1); else write(1, &a, 1); // 완성된 문자를 출력 g_data.count = 0; // 자릿수 처음으로 초기화 } }
sig_usr2 함수
- 클라이언트로부터 SIGUSR2 시그널을 받았을때에 실행
클라이언트로부터 받은 시그널을 1 로 생각하고 문자를 이루는 8개의 비트중 현재 카운트에 해당하는 자리에 1을 넣어줌.
이후 카운트를 1 증가시키는데 이떄 카운트가 8 이라면 1바이트가 완성된것이므로 문자를 출력하고 카운트를 초기화시켜줌void sig_usr2(int signum) // SIGUSR2 시그널을 1에 대응 { char a; (void) signum; g_data.bit[g_data.count] = '1'; //실행시 문자 2진수의 현재 자릿수를 1로 생각하고 넣어줌 g_data.count++; // 자릿수 증가 if (g_data.count == 8) // 8비트를 가득 채울시 { g_data.dec = change_dec(g_data.bit); // 10진수로 변환 a = (char)g_data.dec; write(1, &a, 1); // 완성한 문자 출력 g_data.count = 0; // 자릿수 초기화 } }
int main(int argc, char **argv)
{
char *str;
char *save;
if (argc != 3) //시작시 pid와 문자를 받아왔는지 확인
return (0);
if (check_str(ft_atoi(argv[1], argv[2]))
// 받아온 pid값이 정상범위인지, 숫자로 이루어져 있는지 확인
// 받아온 문자열이 아스키코드로 이루어져있는지 확인
return (0);
while (*argv[2])
{
str = change_bin((int)*argv[2]); //현재 문자를 2진수로 변환
if (str == 0)
return (0);
save = str;
while (*str) //2진수가 저장된 문자열 반복
{
send_msg(ft_atoi(argv[1]), *str);
// 현재 저장된 2진수에따라 서버로 0 또는 1을 전송
str++;
usleep(200);
// 쉬지않고 보낼시 서버가 다 받지 못할 수 있으므로 서버가 수신할 수 있도록 200마이크로초 대기
}
argv[2]++; // 다음 문자로
free(save); // 방금까지 봤던 문자열 저장공간 해제
}
send_end(ft_atoi(argv[1])); // 다 보냈으므로 끝이라는뜻의 \0 전송
exit(0);
return (0);
}
void send_msg(pid_t pid, char a)
{
if (a == '0') // 0이면 SIGUSR1시그널 전송
kill(pid, SIGUSR1);
else if (a == '1') // 1이면 SIGUSR2시그널 전송
kill(pid, SIGUSR2);
}
void send_end(pid_t pid)
{
int i;
i = 0;
while (i != 8)
{
kill(pid, SIGUSR1); // 끝이기때문에 0을 8번 전송해서 \0임을 알림
i++;
usleep(200);
}
return ;
}