오늘은 프로세스간 통신 방법인 메일 슬롯 사용법에 대해서 알아보겠습니다.
메일 슬롯에 대해 약간의 설명을 하자면, 우체통과 비슷하다고 볼 수 있습니다.
아래 그림과 같이 A가 B에게 편지를 보낸다고 할 때, A는 편지를 우체통에 넣고, B는 우체통에서 편지를 찾아가면 됩니다.
이 방식은 매우 편리해서 아래와 같이 A는 우체통에 편지를 여러번 집어 넣을 수 있고, B가 나중에 한번에 찾아갈 수 도 있습니다.
물론 B가 편지를 찾아가지 않는데 A가 편지를 계속 집어 넣기만 한다면 우체통이 터지겠죠?
잘 유의해서 사용하면 편리하게 사용가능합니다.
MFC로 예제를 해보겠습니다. MFC 프로젝트를 생성해주시고, 아래와 같이 버튼 4개를 만들어 줍니다.
대화상자 헤더파일에 메일슬롯 핸들과 전송 데이터를 선언해줍니다.
HANDLE m_hMailSlot; // 메일슬롯 핸들
BYTE m_byData; // 전송 데이터
Create 버튼을 더블 클릭하여 이벤트 처리 함수에 아래와 같이 코딩합니다.
void CMFCApplication1Dlg::OnBnClickedButtonCreate()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
int iMailSize = 40000;
m_hMailSlot = ::CreateMailslot( _T("\\\\.\\mailslot\\MailSlot"), iMailSize, 0, (LPSECURITY_ATTRIBUTES)NULL);
if (INVALID_HANDLE_VALUE == m_hMailSlot)
{
m_hMailSlot = NULL;
AfxMessageBox(_T("CreateMailslot Fail"));
}
}
Send 버튼을 더블 클릭하여 이벤트 처리 함수에 아래와 같이 코딩합니다.
void CMFCApplication1Dlg::OnBnClickedButtonSend()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
BOOL bResult(FALSE);
DWORD dwWrLen(0);
HANDLE hFile;
hFile = ::CreateFile(_T("\\\\.\\mailslot\\MailSlot"),
GENERIC_WRITE,
FILE_SHARE_READ,
(LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
(HANDLE)NULL);
if (INVALID_HANDLE_VALUE != hFile)
{
bResult = ::WriteFile(hFile, &m_byData, sizeof(m_byData), &dwWrLen, (LPOVERLAPPED)NULL);
m_byData++;
if ( FALSE == bResult )
AfxMessageBox(_T("WriteFile Fail"));
::CloseHandle(hFile);
}
else
{
AfxMessageBox(_T("CreateFile Fail"));
}
}
Receive 버튼을 더블 클릭하여 이벤트 처리 함수에 아래와 같이 코딩합니다.
void CMFCApplication1Dlg::OnBnClickedButtonReceive()
{
DWORD dwNextSize(0), dwMsgCnt(0);
BOOL bResult(FALSE);
BYTE byData(0);
DWORD dwReadSize(0);
if (INVALID_HANDLE_VALUE != m_hMailSlot)
{
bResult = GetMailslotInfo(m_hMailSlot, ///< mailslot handle
(LPDWORD)NULL, ///< no maximum message size
&dwNextSize, ///< size of next message
&dwMsgCnt, ///< number of messages
(LPDWORD)NULL); ///< no read time-out
if (TRUE == bResult)
{
if (MAILSLOT_NO_MESSAGE != dwNextSize)
{
if (0 != dwMsgCnt) ///< retrieve all messages
{
bResult = ::ReadFile(m_hMailSlot, &byData, dwNextSize, &dwReadSize, (LPOVERLAPPED)NULL);
if (TRUE == bResult)
{
CString sMsg;
sMsg.Format(_T("Receive Message(%d)"), byData);
AfxMessageBox(sMsg);
}
else
{
AfxMessageBox(_T("ReadFile Fail"));
}
}
}
}
}
else
{
AfxMessageBox(_T("CreateFile Fail"));
}
}
Close 버튼을 더블 클릭하여 이벤트 처리 함수에 아래와 같이 코딩합니다.
void CMFCApplication1Dlg::OnBnClickedButtonClose()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
::CloseHandle(m_hMailSlot);
m_hMailSlot = NULL;
}
위 상태로 실행해 보시면 아래와 같이 작동합니다.
서로 다른 프로세스에서 메일 슬롯으로 통신할 경우, CreateMailslot을 한 곳에서 Send, Receive가 가능하지만 그렇지 않은 곳에서는 Send만 해야합니다.