관리 메뉴

Kim's Programming

IPC(Inter-Process Communication) - MailSlot 본문

Programming/System Programming

IPC(Inter-Process Communication) - MailSlot

Programmer. 2016. 2. 25. 19:16

IPC?


IPC(Inter-Process Communication)은 프로세스간의 통신을 의미합니다. 이는 프포세스간에서 데이터를 주고 받는 것이라 할 수 있습니다. 하지만 프로세스는 일반적으로는 통신을 할 수 없습니다. 프로세스간에 메모리를 공유한다거나 한다면 데이터를 주고 받거나 할 수 있겠지만 각각의 프로세스는 그럴 수 없습니다. 왜냐하면 프로세스 각각은 자신에게 할당된 메모리 공간 이외에는 접근이 불가능하기 때문입니다.  다른 통신수단을 이용해야 합니다. 만약 두 프로세스가 자유롭게 만난다면 어떨까요? 두 프로세스 A,B가 돌아가고 있을때 A의 프로세스가 차지하고 있는 메모리를 B가 건들이게 되면 프로세스A의 저장되지 않은 메모리 위의 데이터는 B에 의해서 손상이 되게 되며 결과적으로는 데이터에 문제가 발생하게 됩니다.  간단히해서 프로세스간 서로 메모리에 접근 못하는 것은 각 프로세스 들의 안정성을 위함입니다.



IPC 종류


IPC 종류는 메일 슬롯과 파이프가 대표적인 IPC 기법입니다.



MailSlot 방식이란?


MailSlot방식의 IPC 기법은 메일슬롯 그 이름 그대로처럼 우체통을 의미합니다.  MailSlot은 Receiver과 Sender가 있으며 Receiver위치에 MailSlot을 걸어높고 Sender가 데이터를 날리게 됩니다. 그러면 Receiver는 Sender가 보낸 데이터를 받게 됩니다.



MailSlot Receiver와 Sender 구성 


    • Receiver 측


      1
      2
      3
      4
      5
      6
      HANDLE CreateMailslot(
          LPCSTR lpName,
          DWORD nMaxMessageSize,
          DWORD lReadTimeout,
          LPSECURITY_ATTRIBUTES lpSecurityAttributes
          );
      cs


          

      1. lpName : 생성하는 메일슬롯의 이름을 결정하는데 사용합니다. 이름이랑 우체통의 주소를 말합니다. 편지를 보낼때 주소가 있어야 제대로 찾아가는 것과 같은 의미입니다. 주소는 \\computername\mailslot\[path]name의 형식을 가지게 됩니다.

      2. nMaxMessageSize : 메일슬롯의 버퍼 크기를 지정하는데 사용됩니다. 0이 전달될 경우 시스템이 허용하는 최대 크기로 지정하게됩니다.

      3. lReadTimeout : 메일 슬롯을 통해 전송된 데이터를 읽기 위해서 파일 입 출력함수인 ReadFile함수가 사용됩니다. 메일 슬롯에서 읽을 데이터가 있다면 데이터들을 읽으면서 ReadFile함수를 빠져나오게 합니다. 하지만 메일 슬롯이 비어있다면 데이터가 채워질때 까지 Blocking상태에 놓이게 됩니다. lReadTimeout은 최대 블로킹 시간은 ms단위로 지정할떄 사용합니다. 데이터가 존재할떄까지 블로킹을 무한히 하고 싶을땐 MAILSLOT_WAIT_FOREVER를 인자로 전달합니다.

      4. lpSecurityAttributes : 핸들을 상속하기 위한 용도의 인자입니다.



    • Sender 측


      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      #include<stdio.h>
      #include<Windows.h>
      #include<tchar.h>
      void main()
      {
          HANDLE hMailSlot = CreateFile(_T("\\\\.\\MailSlot\\MailBox"), ...);
       
          TCHAR Message[50];
          WriteFile(hMailSlot, Message,...);
      }
      cs



      1. 6번째 줄에서는 우편물과 비교하면 편지를 보내기 위해서 통로를 마련하는 부분입니다. 

      2. 9번째 줄에서는 우편물과 비교하면 편지를 보내주는 부분입니다.  

소스 구현


    • Receiver 측


      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      #include<stdio.h>
      #include<tchar.h>
      #include<Windows.h>
       
      #define Slot_Name _T("\\\\.\\mailslot\\mailbox")
       
      int _tmain(int argc, TCHAR *argv[])
      {
          HANDLE hMailSlot;
          TCHAR messageBox[50];
          DWORD bytesRead;
       
          hMailSlot = CreateMailslot(Slot_Name, 0, MAILSLOT_WAIT_FOREVER, NULL);
       
          if (hMailSlot == INVALID_HANDLE_VALUE)
          {
              _tprintf(_T("Cannot Create MailSlot\n"));
              return -1;
          }
       
          _tprintf(_T("---------- Receiving-------------\n"));
       
          while (true)
          {
              if (!ReadFile(hMailSlot, messageBox, sizeof(TCHAR) * 50&bytesRead, NULL))
              {
                  _tprintf(_T("Unable to Read!\n"));
                  return -1;
              }
       
              if (!_tcsncmp(messageBox, _T("exit"), 4))
              {
                  _tprintf(_T("IPC end\n"));
                  break;
              }
       
              messageBox[bytesRead / sizeof(TCHAR)] = 0;
              _tprintf(_T("%s\n"), messageBox);
          }
          CloseHandle(hMailSlot);
          return 0;
      }
      cs


      MailSlot Receive측 소스중에서 ReadFile() 함수의 파라메터들은 다음과 같습니다.

      1
      2
      3
      4
      5
      6
      7
      BOOL ReadFile(
          HANDLE hFile,
          LPVOID lpBuffer,
          DWORD nNumberOfBytesToRead,
          LPDWORD lpNumberOfBytesRead,
          LPOVERLAPPED lpOverlapped
          );
      cs



      1. hFile : 메일 슬롯의 핸들을 파라메터로 전달합니다. 그렇게 하면 ReadFile 함수는 해당 메일 슬롯에 있는 데이터를 읽어들입니다.

      2. lpBuffer : 읽어 들인 데이터를 저장할 버퍼를 지정하는 용도로 사용됩니다.

      3. nNumberOfBytesToRead : 읽어 들일 데이터의 최대 크기를 지정합니다.

      4. lpNumverOfBytesRead : 함수 호출이 완료 된 후에 데이터 크기를 바이트 단위로 얻기 위한 변수를 지정합니다.

      5. lpOverlapped : 일반적으로 NULL을 전달합니다.


    • sender 측


      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      #define _CRT_SECURE_NO_WARNINGS
      #include<stdio.h>
      #include<tchar.h>
      #include<Windows.h>
       
      #define Slot_Name _T("\\\\.\\mailslot\\mailbox")
       
      int _tmain(int argc, TCHAR *argv[])
      {
          HANDLE hMailSlot;
          TCHAR message[50];
          DWORD bytesWritten;
       
          hMailSlot = CreateFile(Slot_Name, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
       
          if (hMailSlot == INVALID_HANDLE_VALUE)
          {
              _tprintf(_T("Cannot Create MailSlot\n"));
              return -1;
          }
       
          _tprintf(_T("-----------Sending-------------\n"));
       
          while (true)
          {
              _tprintf(_T("Send -->"));
              _tscanf(_T("%s"), message);
       
              if (!WriteFile(hMailSlot, message, _tcslen(message)*sizeof(TCHAR), &bytesWritten, NULL))
              {
                  _tprintf(_T("Unable to Write!\n"));
                  return -1;
              }
       
              if (!_tcscmp(message, _T("exit")))
              {
                  _tprintf(_T("IPC end\n"));
                  break;
              }
       
          }
          CloseHandle(hMailSlot);
          return 0;
      }
      cs


      MailSlot Sender측 소스중에서 WriteFile()함수의 파라메터는 다음과 같습니다.


      1
      2
      3
      4
      5
      6
      7
      BOOL WriteFile(
          HANDLE hFile,
          LPCVOID lpBuffer,
          DWORD nNumberOfBytesToWrite,
          LPDWORD lpNumberOfBytesWritten,
          LPOVERLAPPED lpOverlapped
          );
      cs


      1. hfile : 데이터를 읽어 들일 파일을 지정합니다. 여기서는 데이터를 읽어 들일 메일 슬롯을 지정합니다.

      2. lpBuffer : 전송할 데이터가 저장되어 있는 버퍼를 지정합니다.

      3. nNumberOfBytesToWrite : 전송할 데이터 크기를 지정합니다.

      4. lpNumberOfBytesWritten : 함수 호출 완료 후 전송된 실제 데이터의 크기를 바이트 단위로 얻기 위한 변수의 주소로 지정합니다.

      5. lpOverlapped : 일반적으로 NULL으로 전달

위의 소스들의 결과는 다음과 같이 나오게 됩니다.





MailSlot의 특징


메일슬롯은 한쪽 방향으로만 메세지를 전달 할 수 있습니다. 따라서 서로 주고 받는 것을 만들고 싶다면 메일슬롯을 2개 생성해야 합니다.