Minitalk - IPC

nhwang·2022년 5월 24일
0

제한 사항 : SIGUSR1SIGUSR2만을 사용해서 Client의 문자열을 서버로 보내기.
Bonus : 클라이언트와 서버는 매 시그널에 대해 주고받아야 한다.
(UDP처럼 8번주고 8번 받으면 그냥 출력하는 방식X)


핵심 : 보낼 문자의 비트값을 클라이언트에서 0이면 SIGUSR1을, 1이면 SIGUSR2를 보내주는 방식.

  • 초기설계

    Client : 비트마다 SIGNAL전달 매번 usleep사용
    Server : 시그널을 받을 때 마다 index를 증가시키고 8이되면 8비트를 받았다고 가정하고 들어간다.

문제점 : 1000자로 20번 정도 테스트를 해보면 가끔 인식할 수 없는 특수문자 ?류가 노출된다.

현상 : 시그널 주는것과 받는 것을 하나하나 출력해 비교해보니 비트 한 칸씩 밀리는 경우가 있었다.

원인 : 시그널은 보내는 속도에 비해 처리속도가 느리고, 핸들러가 도는 동안 시그널이 오면 해당 시그널은 씹힌다.

받을때마다 클라이언트는 그냥 usleep을 주고 문자열이 끝날 때 까지 8비트씩 던지는데,
만약 서버가 해당 시그널을 처리하는 속도가 늦어져 처리중에 시그널이 오게되면 하나는 씹히고, 한칸씩 밀린다.
클라이언트는 이를 모르게 설계되었기 때문에 그냥 계속 비트를 던진다.

레퍼런스를 참고해봐도 서버의 소화시간을 벌어주기 위해
클라이언트에서 usleep을 그냥 많이 줘서 처리했는데, 이 방식보다 좋은 방식을 찾아보기로 결정.

  • 두 번째 설계
    사실 핸드쉐이크 방식처럼 매 신호를 주고받도록 해야 한다는 걸 이때도 직감하고 있었지만,
    구현이 귀찮아 질까봐 다른 방식으로 구글링을 했음.

sa_mask에 대해 찾다보니 신호를 막는 것 뿐 아니라 조금 기다려줄 수 있다고 생각하고 실험.

sa_mask를 사용하지 않으면 ctrl + c를 하면 메인의 무한루프를 즉시 빠져나오지만,
설정한 경우에는 핸들러가 다 돌고나서 무한루프를 빠져나온다.

이를 통해 다시 1000자 테스트를 여러번 진행했는데, 확실히 첫 설계보다는 양호해진 것을 확인했으나,
오류 문자가 계속 발생해서 세번 째 설계를 진행.

  • 마지막

    AS-IS : 서버가 받았는지 확인하지 않고 8비트씩 보냄. 서버는 8번오면 그냥 출력 (씹힌 것 여부 모름)
    TO-BE : 서버가 비트를 받으면 다시 클라이언트에 시그널을 보내서 그때만 클라이언트가 다음 비트를 보냄.

생각보다 구현이 그리 어렵진 않았다 Client의 문자열 보내는 것을 핸들러 안에서만 구현하도록 하면 되었음.

원래는 메인문에서 클라이언트가 문자열을 8비트마다 계속해서 보내는 함수를 구현하고 거기서 진행했음.
ㄴ> 이 경우 글로벌 필요없고 스태틱 변수만 있으면 해결가능하다.

하지만 이번에 클라이언트는 서버로부터 반응이 왔을때만 비트를 보내주기에 핸들러 안에서 문자열을
보낼 수 있도록 구현하여야 했고, 핸들러의 인자는 문자열을 받을 수 없으니 (핸들러 함수의 인자 한계)
접근을 위해 글로벌 변수를 사용해서 구현.


비트마스킹

Client 부분

if ((*(g_list.string) >> --bitidx) & 1)
		kill(g_list.sv_pid, SIGUSR2);
	else
		kill(g_list.sv_pid, SIGUSR1);

Server

list.buf <<= 1;
		if (sig == SIGUSR2)
			list.buf = list.buf + 1;

핸드 쉐이크 연결

Client

핸들러 내에서 동작해야 하므로 글로벌 변수 사용.

Server

동작 소화 후. kill로 매번 시그널을 클라이언트로 보냄.


프로세스간 통신을 할 때 공유하는 메모리에 접근하는 방식도 있다고 들었지만
해당 과제는 제한사항으로 그렇게 구현하는 것이 아니기에 처음에는 신기하면서도 막막했다.

핸들러가 시그널을 받자마자 돌아가는 함수라는 것과 그것을 설정하는 초기 개념을 받아들이는게 우선이었다.
비트마스킹 구현은 받아들이기 쉬웠지만 새롭고 재밌어서 실험을 많이했음.

1000자씩 여러번 테스트할 경우 ?류의 문자로 깨지는 현상을 발견해서 이를 수정하는데에 쓴 시간이
가장 공부가 되었음. 클라이언트가 그냥 무지성으로 8개씩 보내는 것이 아니라,
서버로부터 확인을 받을때까지 기다리도록 구현함으로서 문제를 해결.


[참고 블로그] :
https://velog.io/@gparkkii/ProgramProcessThread
https://velog.io/@24siefil/minitalk-Inter-Process-Communication
https://velog.io/@two_jay/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0-minitalk

profile
42Seoul

0개의 댓글