이 포스트는 널널한 개발자님의 강의를 듣고 작성한 글입니다.
IPC는 면접때도 질문이 진짜 많이 나오는 내용으로 잘 알아두자!
프로세스라는 것은 공간이 독립적으로 부여된다. 무슨말이냐면 메모리 공간이 주어지는데 이 메모리공간에 대해 다른 프로세스가 접근하지 못하도록 외부접근 차단하는 것을 OS가 보장한다. 만약 이것을 안해주면 내가 저장해 놓은 data를 외부에서 변경시키는 일이 벌어진다. 물론 이것을 의도적으로 해야할 때가 있는데 DMA나 마이컴등이 이런 경우이다. 아무튼 이런 것은 정말 특수한 경우가 아니면 안된다. 만약 OS가 보장하는 것을 뚫고 data를 변경을 시키면 그것은 일명 해킹이라고 부른다.
프로세스가 사용하는 전산자원중에는 독립적인 메모리뿐만 아니라 파일형태로 쓰는게 있는데 이것을 대표적으로 파이프라고 한다.
추가적으로 알아야 할것이 있는데 프로세스간의 통신을 할 수 있는 방법으로는 크게보면 메모리를 이용하는 방식, 쉽게 말해 RAM을 쓰는 것이고 그 다음으로는 file을 이용하는 방식이 있다. 이 2가지 방법이 차이가 있는 것이 file하면 떠올라야 하는 것이 stream이며 file은 시작이 있지만 끝이 조금 애매하다는 것이 특징으로 볼 수 있다. 우리가 fOpen()함수를 통해 파일을 만들면 처음에는 size가 0이다. 조금 웃긴 상황이 우리는 여기다가 write()함수를 통해 데이터를 넣는다. 그 후에 size는 자동증가가 된다. 얼마나 증가하냐면 이 file을 컨트롤해주는 파일 시스테이 제공하는 한계까지 늘어날 수 있다. 그런데 RAM을 쓸데는 가장 중요한 특징이 고정길이이다. RAM은 자원이 매우 제한적이기 때문에 OS한테 요구를 할 때 OS가 얼마나 쓸것인지 강하게 체크한다. 즉 길이를 OS가 강하게 검사를 하는 것이다. 그래서 우리는 할당단계에서 크기를 고정해야 한다.
만약, IPC가 네트워크 개념까지 확장되면 소켓이 등장한다. 이 소켓을 기반으로 TCP 연결이 된 상태에서 또 다른 개념으로 RPC가 나오는데 RPC는 원격 함수 호출로 이 호출을 위해 TCP통신을 한다. 이 부분도 옛날에 쓰던 기술이었는데 최근에 잘 안쓰다가 오늘와서 갑자기 급부상하게 되었는데 그 이유가 RCP가 HTTP3와 관련이 있기 때문이다.
오늘날의 HTTP는 아주 옛날의 TCP와 같은 역할을 하고 있다. 이래서 Web Socket 개념이 나오기 시작했고 이런 개념을 이해하기 시작하면서 RPC 개념이 확장되었다. 웹 기반으로하는 (HTTP를 기반으로) RPC도 고민해야 한다.
본론으로 IPC방법론이 여러가지 있는데 기본적으로 파이프라고 나오면 파일이라 생각하면 된다. 즉, data를 직렬화시켜서 stream으로 data를 주거니 받거니하면 굉장히 유리한 구조이다.
프로세스간에 독립적인 메모리 공간을 보장한다. 그래서 VMS들은 프로세스들한테 attach 되어 있다. 즉, 다른 프로세스가 내 프로세스 VMS 접근이 안된다. 그래서 IPC는 Shared Memory 기반의 기법을 사용하는데 방법은 다음과 같다.
A라는 프로세스의 VMS의 어느부분을 따라 갔을 때 B라는 프로세스의 VMS의 어느부분과의 실제 RAM 메모리 주소가 일치한다면 A가 3을 저장했다고 했을 때 B는 3을 읽어 올 수 있다. 반대의 경우도 가능할 것이다.
또 다른 예로 A가 B한테 보낼 정보가 있으면
1) A의 VMS에 data를 write하고
2) 그 data가 실제 RAM에 저장될 것이고
3) A가 B한테 어떠한 Signal을 보내는데 혹은 Event를 보내는데 그 전에 B는 wait상태가 되고
4) 그 Event를 B가 반환하고
5) 그 data를 읽어들인다.
전역변수?를 통한 양방향 통신: Shared Memory를 확보한 다음에 앞에는 A가 쓰고 B쪽에서는 읽어가고 뒤쪽은 반대로 한다, 근데 중요한 것은 Shared Memory를 쓸 때는 길이가 고정되어 있다.
파일의 경우는 되게 독특한게 뭐냐면 한쪽에서 읽고 한쪽에서 쓰는 방식을 채택한다. data가 섞일 일도 없고 동기화를 덜 신경써도 되기 때문에 직렬화한 데이터를 넘길 때 유리하다.
💡 Tip
우리가 IPC를 할 때 메모리, 파이프, 소켁 RPC등을 사용하는데 추가적으로 윈도우 OS 한정으로 Registry가 있다. 이 레지스트리는 파일보다 더 강력하다. 그리고 레지스트리는 in Memory 상태이다. 그리고 여러 프로세스가 동시접근할 경우 통제도 잘 된다. 즉, file과 Memory의 장점을 둘다 가졌다. 그래서 레지스트리에다가 I/O를 하면 생각보다 속도가 빠르다. (file에 쓰는 것보다 더 빠르다.)
그런데 가끔 특수한 경우가 있는데 exe파일의 경우 혼자 작동하지 않고 DLL을 로딩해서 작동을 한다. 예를 들어 a.exe가 있는데 a.exe는 a.DLL을 로딩한다. 그런데 b.exe도 a.DLL을 쓸수가 있다. 즉, DLL은 로딩되고 여러 프로그램이 참조하는 방식으로 되어 있다.
만약에 3개의 프로그램이 실행되고 3개의 프로세스간에 IPC를 할 수 있을 때 변수 1개정도를 가지고 뭔가 동기화해야 하는 아주 가끔 이런 상황이 있는데 이 변수 1개를 쉽게 공유하는 방법이 DLL안에 전역변수를 선언하고 그 기억공간을 IPC하듯이 같이 쓰는 기법이 있는데 그 기법이 data segmant Pragma기법이다. 이 기법은 생각보다 성능이 매우 뛰어나다. 이 기법을 통해 user mode에서 방화벽을 흉내낼수 있는데 그 중 하나가 WinSocket API를 hook 할 수 있는 방식이다. 이걸 이용한 프로그램이 우리가 인터넷뱅킹을 할때 설치되는 방화벽 비슷한 프로그램이다. 이 방식을 이용하면 DDL Injection을 하는데 runtime 상태에서 작동되므로 인터넷 뱅킹 사용 시 프로세스를 싹 조사하고 감시하다가 끝나면 끝내는 방식을 취한다.