윈도우즈 시스템 프로그래밍을 공부하면서 정리한 글입니다.
7장. 프로세스간 통신 (IPC) 1
I. 프로세스간 통신(IPC)의 의미
- IPC = Inter-Process Communication ( 프로세스 사이의 통신 )
- 통신 : 기본적으로 데이터를 주고 받는 행위
- 대부분 하나의 프로그램 = 하나의 프로세스 but 여러개의 프로세스를 가진 프로그램도 종종 있음
1. 프로세스 사이에서 통신이 이뤄지기 위한 조건
- 서로 통신하고자 하는 프로세스가 만날 수 있는 여건 (공유하는 메모리 영역이 존재)이 되어야 함
- 여건이 허락되지 않으면 전화 or 메신저 같은 보조 수단이 필요
2. 프로세스들이 서로 만날 수 없는 이유
- 프로세스는 서로 데이터를 주고 받을 만한 접선 장소가 없기 때문에 데이터 주고받는 것은 불가능
- 프로세스는 자신에게 할당된 메모리 공간 이외의 접근은 불가능
3. 프로세스들이 만나지 못하게 디자인한 이유
- 안정성을 높이기 위해
II. 메일 슬롯 방식의 IPC
1. 메일 슬롯 (Mail Slot)의 원리
- 파이프와 더불어 대표적인 IPC 기법
- 메일 슬롯 : 편지를 넣을 가느다란 우체통의 입구
- 기본 원리 : 데이터를 주고받기 위해 프로세스가 우체통을 마련
2. 메일 슬롯 (Mail Slot) 구성을 위해 필요한 요소
① Receiver가 준비해야할 것
HANDLE CreateMailslot (
LPCTSTR lpName,
DWORD nMAXMessageSize,
DWORD lReadTimeout,
LPSECUritY_ATTRIBUTES lpSecurityAttributes
);
1) lpName : 생성하는 메일 슬롯의 이름
- 주소의 기본 형식 : \\computer name\mailslot\[path] name
2) nMaxMessageSize : 메일 슬롯의 버퍼 크기를 지정
- 0을 전달할 경우 시스템이 허용하는 최대 크기로 지정
3) lReadTimeout : 최대 블로킹 시간을 ms 단위로 전달
- 메일 슬롯은 전소오딘 데이터를 읽기위해 파일 입/출력 함수 ReadFile 함수를 이용
- 메일 슬롯이 비어 있다면 데이터가 채워질 때 까지 Blocking 상태에 놓임
- 0을 전달하면 데이터가 있든 없든 블로킹 상태를 빠져나와 다음 단계를 실행
- MAILSLOT_WAIT_FOREVER을 인자로 전달하면 데이터가 존재할 때 까지 블로킹 상태에 놓임
4) lpSecurrityAttributes : 핸들의 상속 여부를 지정
5) 함수의 변환 타입 : HANDLE
=> 메일 슬롯은 커널에 의해 관리되는 리소스 이므로 커널 오브젝트가 생성되며, 그 핸들이 반환됨
② Sender가 준비해야 할 것
- 메일 슬롯 이름을 알아야 함 (&주소 ( 디렉토리))
ex)
HANDLE hMailSlot;
hMailSlot=CreateFile("\\\\.\\mailslot\\ ", ...); // 파일을 생성하거나 개방할때 사용
CHAR message[50];
WriteFile(hMailSlot, message, ...);
- CreateFile, WriteFile : Windows에서 제공하는 파일 관련 시스템 함수 ( <-> ANSI 표준함수)
HANDLE hMailSlot;
hMailSlot=CreateFile("\\\\.\\mailslot\\ ", ...); // 파일을 생성하거나 개방할때 사용
CHAR message[50];
WriteFile(hMailSlot, message, ...);
- CreateFile, WriteFile : Windows에서 제공하는 파일 관련 시스템 함수 ( <-> ANSI 표준함수)
- CreateFile을 통해 메일 슬롯으로 보내기 위한 통로(리소스)를 형성
=> 데이터 전송을위한 Data Stream을 형성
- 메일 슬롯은 파일이 아니지만 파일 입/출력 함수를 사용
-> Windows 파일 시스템을 기반으로 구현되어 있기 때문
- 주소 골격 : \\computername\mailslot\[path] name
- 주소에서 'mailslot' 부분은 바뀌지 않음
- computername에 '.'의 의미 : 로컬 컴퓨터
=> 데이터 전송을위한 Data Stream을 형성
- 메일 슬롯은 파일이 아니지만 파일 입/출력 함수를 사용
-> Windows 파일 시스템을 기반으로 구현되어 있기 때문
- 주소 골격 : \\computername\mailslot\[path] name
- 주소에서 'mailslot' 부분은 바뀌지 않음
- computername에 '.'의 의미 : 로컬 컴퓨터
- Sender 프로세스는 우체통(메일 슬롯)의 주소를 알고 있어야 데이터 전송이 가능
- 메일 슬롯 = 메모리 공유 역할
- 데이터 전송이 양방향이 아닌 단방향(우체통)
- 여러개의 리시버가 같은 주소를 가질 수 있음
=> 센더가 그 주소로 전송하면 모든 메일 슬롯에 데이터 전송이 가능 (브로드 케스팅)
- CreateFile : 파일 만들거나 오픈
- WriteFile : 파일에 데이터 작성
- IPC 메일 슬롯을 이용하지 않고 파일만으로 데이터를 주고받을 수 있음
ex)
프로세스 A가 파일 a.txt를 만들고 프로세스 B가 a.txt를 읽음
=> BUT 안정성에 문제가 있음 -> ∴ 메일 슬롯을 이용
ex) Receiver.cpp
#define SLOT_NAME _T("\\\\.\\mailslot\\mailbox");
int _tmain(int argc, LPTSTR argv[]) {
HANDLE hMailSlot;
TCHAR messageBox[50];
DWORD bytesRead;
hMailSlot = CreateMailSlot (
SLOT_NAME,
0,
MAILSLOT_WAIT_FOREVER,
NULL
);
ReadFile(hMailSlot, messageBox, sizeof(TCHAR)*50, &bytesRead, NULL);
closeHandle(hMailSlot); // UC 1줄여 커널 오브젝트의 소멸을 도움
ex) Sender.cpp
#define SLOT_NAME _T("\\\\.\\mailslot\\mailbox");
int _tmain(int argc, LPTSRT argv[]) {
HANDLE hMailSlot;
TCHAR message[50];
DWORD bytesWritten;
hMailSlot=CreateFile ( // Receiver과 연결을 만들기 위해
SLOT_NAME,
GENERIC_WRITE, // 여기서부터
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL // 여기까지 거의 고정
);
_fgetts(message, sizeof(messsage)/sizeof(TCHAR), stdin);
WriteFile(hMail, message, _tcslen(message)*sizeof(TCHAR), &bytesWritten, NULL);
CloseHandle(hMailSlot);
- 메일 슬롯 주소에서 '.'는 컴퓨터 자신, '*'는 모든 컴퓨터
=> 브로드 케스팅 이용 가능
III. Signaled vs Non-Signaled => 커널 오브젝트의 상태
1. 상태에 대한 이해
- 상태(state)라는 용어를 사용하는 이유는 변하기 때문
- signaled (신호를 받는 상태)와 Non-Signaled (신호를 받지 않는 상태)
- 커널 오브젝트를 구성하는 멤버 변수 중 하나가 상태 정보를 저장함
=> TRUE : Signaled FALSE : Non-Signaled
2. 프로세스 커널 오브젝트 상태 (state)에 대한 이해
- 프로세스가 생성될 때 프로세스 커널 오브젝트가 생성됨
=> 처음 상태 : Non-signaled
- 프로세스가 종료되면 Signaled 상태로 변경됨
- Signaled 된 커널 오브젝트는 Non-Signaled 상태로 변경되지 않음
=> 종료된 프로세스를 다시 재개하지 못하기 때문 ( 새로운 프로세스를 다시 실행해야 함)
3. 커널 오브젝트의 두가지 상태를 확인하는 용도의 함수
- 커널 오브젝트의 상태를 확인하는 대표적인 함수
ex) DWORD WaitForSingleObject (
HANDLE hHandle, // 확인하려는 커널 오브젝트의 핸들
DWORD dwMilliseconds // 커널 오브젝트가 Signaled 될 때 까지 기다릴 수 있는 최대 시간
);
- dwMilliseconds에 IFINITE 인자 전달시 Signaled 될 때까지 기다림
- WaitForSingleObject 반환값
1) WAIT_OBJECT_0 : 커널 오브젝트가 Signaled 되었을 때 반환값
2) WAIT_TIMEOUT : Signaled 되지 않고 dwMillisecons가 다 되었을 때
3) WAIT_ABANDONED : 오류 발생시
- 이런 상황에서 WaitForSingleObject 사용
참고 : 뇌를 자극하는 윈도우즈 시스템 프로그래밍. 윤성우 저