Windows_/Windows32_API

Windows :: IPC MailSlot을 이용한 프로세스간 통신

sosal 2014. 7. 24. 01:05
반응형

/*

 * http://sosal.kr/

 * made by so_Sal

 */




프로세스간 통신? ::
독립된 두 A, B 프로세스가 서로 데이타를 주고 받는것, or 메모리 공유

보통 하나의 프로그램이 하나의 프로세스라고 생각하시는 분이 많으신데,
하나의 프로그램이 여러개의 프로세스를 생성하는 경우도 많습니다.
(특히 서버측 프로그램이 다중 프로세스로 구현되는 경우가 많습니다.)

다중 프로세스 프로그램의 경우, 각각의 프로세스가
서로 데이타를 주고받는 경우가 십중팔구입니다.

흔히 A라는 프로세스가 B에게 하나씩 데이타를 send 해주고,
B 프로세스는 A가 보내는 정보를 recieve 한다고 생각합니다.
하지만 프로세스간 통신은 메모리 공유한다는것이라는 엉뚱한 결론이 도출됩니다.
곧 프로세스간 통신은 메모리 공유입니다.

단 그 메모리 공유는 B 프로세스가 A프로세스의 메모리를
직접 침투하는게 아니라, temp 메모리 공간을 새로 생성하여
A라는 프로세스는 temp 메모리 공간에 데이타를 놓고,
B 프로세스는 temp메모리 공간에서 정보를 가져갑니다.

다양한 프로세스 통신을 공부 하실건데, 단순히 lib 함수만 알고 쓰는것보다
이러한 함수들의 메커니즘을 이해하는것이 더 중요합니다.

A 프로세스 , B프로세스가 있다고 가정하면, 둘의 메모리 공간은
완전히 분리되어있습니다.
분리해서 관리하는 대상은? : 운영체제. (커널)

A 프로세스는 자기에게 할당된 메모리를 절.대 벗어날 수 없습니다.
B 프로세스 역시 절.대 벗어날 수 없습니다.
그렇기 때문에, 어떤 메모리 공간을 공유해서 정보를 주고받는다?
가 허용이 되지 않습니다. 메모리가 분리되어있기 때문이죠.

그럼 왜 이것을 허용하지 않을까요?.
허용할 수 없어서 못하는것이 아니라 일부러 막아놓은것입니다.
실행되고 있는 A 프로세스가 B 프로세스의 메로리 공간에
접근할 수 있도록 허용을 한다면, A프로세스는 B프로세스의 실행에
영향을 미칠 가능성이 생깁니다.
so, 안정성때문에 프로세스간의 메모리를 완벽히 분리하고,
할당된 메모리 이외에는 접근하지 못하도록 막아놓고있습니다.
이일은 물론 운영체제가 합니다.

그럼, 위에서 temp라는 메모리를 할당하여 메모리 공유를 통해
통신을 한다고 했는데, 이 일은 누가 할까요?
프로세스에겐 능력이 없죠. 이일은 운영체제가 합니다.


메일슬롯
사전적인 뜻은 우체통의 구멍(입구)를 말하는 단어입니다.
일반적인 OS (리눅스 유닉스 윈도우 등등등..) 공통 용어입니다.
거의 대부분 유사하게 구현 되어있고 같은 기능을 합니다.

정보를 받고싶은 프로세스는 우체통(메모리공간)을 만듭니다.
이 영역은 받고싶은 프로세스가 함수호출을 이용해 간접적으로
접근 가능한 메모리 영역입니다.

정보를 주고싶은 프로세스는 정보를 받으려는 프로세스가 만든
우체통(메모리공간)에 데이타를 입력합니다.

마지막으로 정보를 받으려는 프로세스는 우체통(메모리 공간에)
저장되어있는 데이타를 가져갑니다.


통신이라고 말하면 양방향을 가장 먼저 떠올립니다.
하지만 우체통을 마련한 reciever가 우체통을 통해
다시 정보를 보낼 수 있을까요? No! 불가능합니다.
우체국에다 줘야지 자기 우체통해다 넣는다고
편지가 날라가지 않겠죠!!

결국 통신은 단.방.향 입니다.

그럼, 우체통이 하나인데, 그 우체통의 주인이
여러명이라면? 한방의 전송으로 여러명이 정보를 같이 받아먹음!
(실제로는 말도 안되는 일이지만... 윈도우즈에선 가능합니다.)
이게 바로 BroadCast (방송)의 원리입니다.


그럼.. 이제 남은건 코오딩!!



Receiver :: 우체통을 생성하고!!! (CreateMailslot)
Sender   :: 우체통에 연결을 하고!! (CreateFile)
Sender   :: 배달!! WriteFile
Receiver :: 이제 받아와서 먹으면 됨. ReadFile

메일 관련된 이야기를 하는데, 왜 File이냐구요?
왜 File 관련된 함수를 쓰냐구요? 흠..
메모리 공간(우체통)을 생성하였다, 공유하겠다. 즉
Sender는 메모장(파일)을 새로 만들어서 거기에 글자를 쓰고,
Receiver는 메모장(파일)을 open해서  글을 가져간다면
통신이 된것이겠죠? IPC 이용하지 않고 파일만 이용하여
통신이 가능합니다. (하지만 단점이 많죠, 특히 안정성.. 여기서 나열하진 않겠습니다.)
이러한 단순한 생각을 그대로 반영한것이 IPC입니다.
IPC 역시 결국에는 파일시스템으로 구성되어 있습니다.
MS에서
" File system으로 구성되어있다는걸 노골적으로 표현하기 위해 File 관련 함수로 이름을 정했다 "
라고 책들에서 이야기를 하네요.

리눅스를 공부하신 분이라면 더욱 잘 이해하실 수 있겠습니다 ^-^
(리눅스에선 소켓, 파일 서술자 등 모두 파일로 관리되죠!!)


위에서 단방향이라구 말했죠?
Receiver는 전송 불가능합니다.!!!

CreateMailslot :: 우체통 생성
CreateFile :: 새로운 파일을 생성하거나, open 할때 사용하는 함수
WriteFile :: 파일에다 쓰기를 위한 함수
ReadFile :: 데이타를 읽기위한 함수

좀더 자세히 보겠습니다.

:: CreateMailslot ::
HANDLE CreateMailslot (LPCTSTR lpName, DWORD nMaxMessageSize,
                 DWORD lReadTimeout, ref SECURITY_ATTRIBUTES lpSecurityAttributes);

lpName :: 컴퓨터 이름
#define SLOT_NAME _T((\\.\mailslot\[Path]Name)
중간에 " . " (쩜) 의미는 자기 자신의 컴퓨터를 의미합니다.
Receiver의 우체통이 자기것이 아니라면 누구의 것이겠나요? ㅎㅎ

nMaxMessageSize :: 메일슬록 버퍼크기, 0 :: 허용 최대치
lReadTimeout :: ReadFile 함수 특성
lpSecurityAttributes :: 보안설정 (NULL 일시 default)

:: CreateFile() ::
HANDLE CreateFile( LPCTSTR lpFileName, DWORD dwDesiredAcess
      DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurity Attribute
      DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
      HANDLE hTemplateFile
);

LPCTSTR lpFileName //파일, 경로이름

DWORD dwDesiredAcess // 접근타입
      GENERIC_READ / GENERIC_WRITE ( 읽기전용 / 쓰기전용 )

DWORD
dwShareMode // 파일의 공유모드
 0 / FILE_SHARE_READ / FILE_SHARE_WRITE

LPSECURITY_ATTRIBUTES lpSecurity Attribute 상속지정포인터
(NULL / SECURITY_ATTRIBUTES)

DWORD dwCreationDisposition
CREATE_NEW – 같은 이름의 파일이 있다면 생성하지 않음
CREATE_ALWAYS – 같은 이름의 파일이 있다면 삭제후 생성
OPEN_EXISTING – 파일이 없다면 에러
OPEN_ALWAYS – 같은 이름의 파일이 없다면 생성
TRUNCATE_EXISTING – 초기화 된 파일열기

DWORD dwFlagsAndAttributes, // 파일 속성
FILE_ATTRIBUTE_ARCHIVE – 아카이브 속성
FILE_ATTRIBUTE_HIDDEN – 숨김 파일
FILE_ATTRIBUTE_NORMAL – 일반 파일 (무속성)
FILE_ATTRIBUTE_OFFLINE – 연결되지 않은 파일
FILE_ATTRIBUTE_READONLY – 읽기전용파일
FILE_ATTRIBUTE_SYSTEM - OS system 파일
FILE_ATTRIBUTE_TEMPORARY – 임시저장 파일

HANDLE hTemplateFile
파일의 추가속성 (NULL)

:: WriteFile ::
BOOL WriteFile(
    HANDLE hFile, LPCVOID lpBuffer,
    DWORD nNumberOfBytesToWrite,
    LPDWORD lpNumberOfBytesWritten,
    LPOVERLAPPED lpOverlapped
);
HANDLE hFile  // 쓰기를 원하는 파일 커널 오브젝트를 가리키는 핸들
LPCVOID lpBuffer // 전달 버퍼
DWORD nNumberOfBytesToWrite // 전달 버퍼의 크기
LPDWORD lpNumberOfBytesWritten //실제 기록된 크기
LPOVERLAPPED lpOverlapped // 비동기 입출력 (아닐경우 NULL)

:: ReadFile ::

BOOL ReadFile(
   HANDLE hFile, LPVOID lpBuffer,
   DWORD nNumberOfBytesToRead,
   LPDWORD lpNumberOfBytesRead,
   LPOVERLAPPED lpOverlapped
);
HANDLE hFile // 읽기를 원하는 파일 커널 오브젝트를 가리키는 핸들
LPVOID lpBuffer //파일의 내용을 복사할 버퍼
DWORD nNumberOfBytesToRead // 읽을 수 있는 최대 버퍼의 크기
LPDWORD lpNumberOfBytesRead //실제 읽은 버퍼의 크기
LPOVERLAPPED lpOverlapped //비동기 입출력 (아닐경우 NULL)


==
마지막으로 예제소스 링크입니다.
LINK_