윈도우즈 시스템 프로그래밍 7장-세션2
메인슬롯 방식의 IPC
메인슬롯의 원리
메인 슬롯은 데이터를 주고받기 위해 프로세스가 우체통을 마련하는 것과 유사한 일을 해준다.
앞선 세션에서 말했듯 프로세스는 서로 직접적인 통신을 불허한다.
그래서 리시버 프로세서는 정보를 받기 위한 우체통인 메인 슬롯을 필요로 한다.
이 메인 슬롯은 접선 장소의 역할을 하여준다.
메인 슬롯의 필요 구성 요소
메인슬롯을 생성하는 메인함수의 멤버변수는 다음과 같다.
📍멤버
메인 슬롯의 이름을 지정하는 LPCSTR타입의 변수
메인 슬롯의 버퍼크기(최대크기)를 지정하는 DWORD타입의 변수
대기시간을 지정하기 위한 DWORD타입의 변수
핸들의 상속을 위한 LPSECURITY_ATTRIBUTES
위 CreateMailslot()
함수를 실행시키면 커널 오브젝트의 핸들이 반환된다.
메일슬롯 역시 커널에 의해 관리되는 리소스이므로 커널 오브젝트가 생성되고, 이 커널의 핸들이 반환되게 되는 것이다.
sender의 요소
리시버에게 정보를 보내기 위해서는 리시버의 주소(메일슬롯 주소)를 알아야한다.
참고로, sender과 Receiver은 동시에 혹은 같은 팀에서 개발이 진행된다.
코드로 보는 예제
#include <windows.h>
#include <stdio.h>
#include<tchar.h>
#define SlotName _T("\\\\.\\mailslot\\sample_mailslot")
int _tmain(int argc, TCHAR* argv[]) {
HANDLE hMailSlot;
TCHAR message[256];
DWORD Read;
hMailSlot = CreateMailslot(SlotName, 0, MAILSLOT_WAIT_FOREVER, NULL);
if (hMailSlot == INVALID_HANDLE_VALUE) {
_fputts(_T("CreateFile failed with %d.\n", GetLastError()),stdout);
return 1;
}//파일 생성의 실패를 의미
_fputts(_T("Message\n"), stdout);
while (1) {
if (!ReadFile(hMailSlot, message, sizeof(TCHAR) * 256, &Read, NULL)) {
_fputts(_T("Can`t Read this Slot\n"), stdout);
CloseHandle(hMailSlot);
return 1;
}
if (!_tcsncmp(message, _T("exit"), 4)) {
_fputts(_T("Exit this Slot\n"), stdout);
break;
}
message[Read / sizeof(TCHAR)] = 0;
_fputts(message, stdout);
}
CloseHandle(hMailSlot);
return 0;
}
혹시나 이 책을 읽으면서 어라 왜 에러가 뜨지 싶은 나같은 분이 있다면(나는 혼자서 코드를 짰다가 에러가 떠서 저자분 코드도 복붙해보고 막 그랬었다)
이 단계에서는 아직 전송하는 sender가 만들어지지 않았기 때문에 멈춰있는듯한 오류가 뜨는 상태가 정상이다.
sender만들기
sender은 CreateFile을 이용하여 파일을 만들어 전송하는 것과 유사한 방식으로 코드를 짜면 된다.
#include <windows.h>
#include <stdio.h>
#include<tchar.h>
#include<locale.h>
#define SlotName _T("\\\\.\\mailslot\\sample_mailslot")
int _tmain(int argc, TCHAR* argv[]) {
HANDLE hMailSlot;
TCHAR message[256];
DWORD write;
setlocale(LC_ALL, "korean");
hMailSlot = CreateFile(SlotName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hMailSlot == INVALID_HANDLE_VALUE) {
_fputts(_T("잘못된 메일슬롯입니다\n"), stdout);
return 1;
}
while (1) {
_fputts(_T("CMD>>"), stdout);
_fgetts(message, sizeof(message) / sizeof(TCHAR), stdin);
if (!WriteFile(hMailSlot, message, _tcslen(message) * sizeof(TCHAR), &write, NULL)) {
_fputts(_T("write가 불가합니다\n"), stdout);
CloseHandle(hMailSlot);
return 1;
}
if (!_tcsicmp(message, _T("exit"))) {
_fputts(_T("프로그램을 종료합니다\n"), stdout);
break;
}
}
CloseHandle(hMailSlot);
return 0;
}
나는 영어로 오류를 짜는 것이 너무 어렵고 귀찮아서 앞에서 배운 locale을 사용하여 한글을 콘솔에서 사용할 수 있도록 바꾸었다.
참고로 이 파일만 실행하면 오류가 잘못된 메일슬롯이라는 오류가 뜨며 receiver을 먼저 실행 후 띄워야 정상적인 작동이 된다.
그 이유는 파일을 만드는 과정에서 전달인자로 OPEN_EXISTING을 전달하고 있기 때문이다.
파일 슬롯에 대한 설명
메일슬롯은 단방향 통신만 가능하다는 특징이 있다.
그렇기 때문에, 한쪽 방향으로만 메시지 전달이 가능하다는 문제가 있을 수 있다.
ipc와 메일슬롯
우리가 지금까지 배운 예제만으로 양방향 통신을 구현하는 것이 가능할까?
우선 저자가 던져준 힌트를 읽어보면 두 개 이상의 메일슬롯을 구현해낸다면 채팅 프로그램과 유사하게 작동하는 것을 만들 수 있다고 설명이 되어있다.
양방향 통신 계획 세우기
지금 우리가 만든 메일슬롯에 대해 간단하게 정리하면 sender1이 receiver로 정보를 보내는 방식으로 되어있다.
sender1->receiver
을 양방향으로 만들기 위해서는 sender1->reciever->sender2
의 형태로 수정을 하면 된다.
코드로 작성하기
작성한 코드는 길기도 하고 조금만 생각하면 크게 구성자체는 어렵지 않아서 따로 첨부하지 않았다.
유의점은 메시지를 두개 선언해서 따로 관리하는 것이 훨씬 코드를 짜고 관리하는 데에 쉽다는 것과 slot의 이름을 따로 두어야한다는 것 정도가 있다
참고로 나의 경우엔 term을 두지 않았더니 단방향으로만 짰을 때에는 문제가 되지 않았으나 양방향으로 짜니 문제가 생겼어서 이 부분도 책에 나온 예제를 따라하실 분이라면 sleep 등으로 텀을 주는 과정이 꼭 필요할 것 같다.
댓글남기기