본문 바로가기
프로그래밍/운영체제

C/C++ IPC인 mailslot에 대한 이해

by Hwan2 2020. 1. 16.
728x90
반응형

 

 

 

Mail Slot은 프로세스간에 데이터를 주고받기 위한 방식중 하나입니다.

 

프로세스는 기본적으로 자신에게 할당된 메모리를 공유할 수 없기 때문에 여러가지 방법으로 데이터를 주고 받습니다.

 

Mail Slot은 파일에 데이터를 적어 놓고 다른 프로세스들이 해당 파일에 접근해서 데이터를 읽어오도록 합니다.

 

따라서 파일을 읽을 수 있는 함수인 ReadFile() 함수와 데이터를 작성할 수 있는 WriteFile() 함수가 사용됩니다.

 

 

MailSlot의 특징은 다음과 같습니다.

 

1. 단방향 통신이다.

CreateMailslot() 함수로 보낼 메일 슬롯의 파일을 생성하고 WriteFile()함수를 통해 입력을 하게되고

CreateFile() 함수를 통해 파일을 열어 해당 내용을 읽어올 수 있는 ReadFile()함수를 사용하게 됩니다.

하지만 파일을 읽는 특성상 while(1)에 입력값이 있는지 혹은 읽을 값이 있는지를 계속해서 확인해야 합니다.

따라서 양방향 통신을 하게 하려면 CreateMailslot()과 CreateFile()함수를 동시에 만들어야 하죠.

또한 자연스럽게 작동하게 하려면 이 둘을 쓰레드 형태로 분리시켜야 합니다.

 

2. 브로드케스트를 한다.

Mailslot특성상 하나의 파일에 데이터를 입력하고 다른 프로세스들은 해당 파일을 참조해 읽기 때문에 

쓰는 프로세스와 읽는 프로세스가 나뉘어져 있습니다. 여기서 다른 프로세스가 ReadFile()로 데이터를 읽으면

다른 프로세스들이 못읽는 것이아니라 Mailslot을 참조하고 있는 모든 프로세스들이 동일한 내용을 받아서 읽을 수 있기 때문에

브로드케스트를 한다고 말합니다.

 

 

CreateMailslot()은 다음과 같이 구성되어 있습니다.

 

HANDLE CreateMailslot(
    LPCTSTR lpName,
    DWORD nMaxMessageSize,
    DWORD lReadTimeout
    LPSECURITY_ATTRIBUTES lpSecurityAttributes
);
Colored by Color Scripter
cs

 

 

 

CreateMailslot()함수로 mailslot을 만들게 되면 다음과 같은 상태가 됩니다.

"지정된 경로의 mailslot파일에 접근할 준비가 완료됐습니다."

 

 

그럼 해당 경로로 가서 mailslot파일을 읽어와야 합니다.

파일을 읽어오는 것이기 때문에 ReadFile()함수가 사용됩니다.

 

 

ReadFile()

BOOL ReadFile(
    HANDLE hFile,
    LPVOID lpBuffer,
    DWORD nNumberOfBytesToRead,
    LPDWORD lpNumberOfBytesRead,
    LPOVERLAPPED lpOverlapped
);

 

 

 

 

 

CreateMailslot()함수를 통해 데이터를 읽을 준비가 완료되면 해당 파일에 데이터를 보내는 작업이 필요합니다.

 

해당 작업은 CreateFile() 함수와 WriteFile() 함수를 통해 작업이 가능합니다.

 

 

 

CreateFile() 함수는 다음과 같이 정의되어 있습니다.

 

HANDLE CreateFile(
    LPCTSTR lpFileName,
    DWORD dwDesiredAccess,
    DWORD dwShareMode,
    LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    DWORD dwCreationDisposition,
    DWORD dwFlagsAndAttributes,
    HANDLE hTemplateFile
);
​

 

 

 

dwDesiredAccess(ReMarks) 파일 및 디렉터리 접근 권한

 GENERIC_ALL  가능한 모든 엑세스 권한 허용
 GENERIC_EXECUTE  엑세스 실행 권한 
 GENERIC_WRITE  쓰기 권한 
 GENERIC_READ  읽기 권한
 MAXIMUM_ALLOWED  최대한 많은 권한 허용 
 DELETE  삭제 권한 
 READ_CONTROL  보안, DACL 디스크립터를 읽을 수 있는 권한
 WRITE_DAC  DACL에 대한 쓰기 권한
 WRITE_OWNER  소유자에게 쓰기 권한
 SYNCHRONIZE  엑세스 동기화

참고 : https://docs.microsoft.com/ko-kr/windows/win32/secauthz/access-mask

 

 

dwShareMode 파일 및 디렉터리 공유 모드

 0   다른 프로세스가 파일 또는 디렉토리에 대한 읽기, 쓰기, 삭제를 못하게 막는다.
 FILE_SHARE_DELETE  삭제 요청을 허용(이름 바꾸는 작업도 포함) 
 FILE_SHARE_READ  읽기 요청을 허용
 FILE_SHARE_WRITE  쓰기 요청을 허용

참고 : https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea

 

lpSecurityAttributes

 

SECURITY_ATTRIBUTES 구조에 대한 포인터 입니다.

NULL 전달시 return된 핸들 값은 상속될 수 없으며 기본 보안설정이 됩니다.

 

SECURITY_ATTRIBUTES

typedef struct _SECURITY_ATTRIBUTES {
  DWORD  nLength;
  LPVOID lpSecurityDescriptor;
  BOOL   bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;​

 

 nLength  구조체의 크기 설정
 lpSecurityDescriptor  엑세스 토큰에 대한 설정, , NULL입력 시 기본 보안설정
 bInheritHandle  반환된 핸들을 상속할지 여부 결정.

참고 : https://docs.microsoft.com/ko-kr/previous-versions/windows/desktop/legacy/aa379560(v=vs.85)

 

 

 

dwCreationDisposition

 CREATE_ALWAYS  항상 새 파일을 만듦
 CREATE_NEW  파일이 존재하지 않는 경우에만 새 파일 만듦
 OPEN_ALWAYS   항상 파일을 연다.
 OPEN_EXISTING  파일 또는 장치가 있는 경우에만 연다.
 TRUNCATE_EXISTING  파일이 존재한다면 기존 내용을 모두 지운 후 연다.

 

 

 

dwFlagsAndAttributes

파일에 대한 속성값 정의

 FILE_ATTRIBUTE_ARCHIVE   해당 파일을 보관(쓰기)할 때 사용 
 FILE_ATTRIBUTE_ENCRYPTED  파일이나 폴더를 암호화로 지정합니다. 파일의 경우 모든 내용을 암호화하며 폴더의 경우 새로 만들어지는 파일을 암호화합니다.
 FILE_ATTRIBUTE_HIDDEN  파일을 숨김으로 지정
 FILE_ATTRIBUTE_NORMAL   파일에 대한 속성을 지정하지 않는다.
 FILE_ATTRIBUTE_OFFLINE   연결되지 않은 저장 장치에 있어 즉시 사용할 수 없는 파일  
 FILE_ATTRIBUTE_READONLY  읽기 전용파일로 설정
 FILE_ATTRIBUTE_SYSTEM   시스템 파일로 설정
 FILE_ATTRIBUTE_TEMPORARY   임시 파일로 지정

 

 

TemplateFile

 

GENERIC_READ 엑세스 권한을 가진 템플릿 파일의 유효한 핸들입니다.

생성된 파일에 대한 속성및 확장을 제공하는 템플릿입니다.

사용하지 않을 경우 NULL 값을 사용합니다.

 

 

 

 

 

 

WirteFile()

 

WriteFile은 파일에 데이터를 쓰개해주는 함수입니다.

 

BOOL WriteFile(
  HANDLE       hFile,
  LPCVOID      lpBuffer,
  DWORD        nNumberOfBytesToWrite,
  LPDWORD      lpNumberOfBytesWritten,
  LPOVERLAPPED lpOverlapped
);
 hFile   핸들을 지정합니다. 즉, 파일에 데이터를 입력할 해당 핸들을 지정합니다.
 lpBuffer  전송할 데이터를 저장할 수 있는 버퍼입력
 nNumberOfBytesToWrite  전송할 데이터의 크기를 지정
 lpNumberOfBytesWritten  데이터를 보낸 후 보낸 길이를 저장
 lpOverlapped  비동기 입출력을 사용할 경우 OVERLAPPED 구조체를 정의해 사용하고 그렇지 않을 경우엔 NULL 입력.

 

 

 

다음은 예제 입니다.

 

mailslot-sender

//visual studio 2017
//mailslot-sender

#include <iostream>
#include <Windows.h>

using namespace std;
#define SLOT_NAME "\\\\.\\mailslot\\mailbox"

int main(void) {

    HANDLE mail_slot;
    char buffer[1024];
    unsigned long len;

    mail_slot = CreateFile(
        SLOT_NAME,
        GENERIC_WRITE,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );

    while (1) {
        cin >> buffer;
        WriteFile(mail_slot, buffer, sizeof(buffer), &len, NULL);
    }

    CloseHandle(mail_slot);
    return 0;
}
​

 

 

 

 

mailslot-recive

//visual studio 2017
//mailslot-recive

#include <Windows.h>
#include <iostream>

using namespace std;

#define SLOT_NAME "\\\\.\\mailslot\\mailbox"

int main(void) {

    HANDLE mail_slot;
    char buffer[1024];
    unsigned long len;

    mail_slot = CreateMailslot(
        SLOT_NAME,
        0,
        MAILSLOT_WAIT_FOREVER,
        NULL
    );

    while (1) {
        ReadFile(mail_slot, buffer, sizeof(buffer), &len, NULL);
        cout << buffer << endl;
    }

    CloseHandle(mail_slot);
    return 0;
}
​

 

 

 

 

 

반응형

댓글


스킨편집 -> html 편집에서