Using a Mailslot for IPC
Mailslots provide one-way communication. Any process that creates a mailslot is amailslot server. Other processes, calledmailslot clients, send messages to the mailslot server by writing a message to its mailslot. Incoming messages are always appended to the mailslot. The mailslot saves the messages until the mailslot server has read them. A process can be both a mailslot server and a mailslot client, so two-way communication is possible using multiple mailslots.
A mailslot client can send a message to a mailslot on its local computer, to a mailslot on another computer, or to all mailslots with the same name on all computers in a specified network domain. Messages broadcast to all mailslots on a domain can be no longer than 400 bytes, whereas messages sent to a single mailslot are limited only by the maximum message size specified by the mailslot server when it created the mailslot.
Key Point: Mailslots offer an easy way for applications to send and receive short messages. They also provide the ability to broadcast messages across all computers in a network domain.
本质上来说:A mailslot is a pseudo file that resides in memory, and you use standard file functions to access it. The data in a mailslot message can be in any form, but cannot be larger than 424 bytes when sent between computers. Unlike disk files, mailslots are temporary. When all handles to a mailslot are closed, the mailslot and all the data it contains are deleted.
A mailslot server is a process that creates and owns a mailslot. When the server creates a mailslot, it receives a mailslot handle.
A mailslot client is a process that writes a message to a mailslot. Any process that has the name of a mailslot can put a message there.
邮件槽是围绕Windows文件系统接口设计出来的。客户机和服务器应用需要使用标准的Win32文件系统I/O函数,如ReadFile和WriteFile等,以便在邮件槽上收发数据,同时利用Win32文件系统的命名规则。
邮件槽标识遵守下述命名规则:
//server/Mailslot/[path]name
第一部分 //server 对应服务器名,在其上创建邮件槽并在上面运行服务器程序。取值可以是小数点(.),一个星号(*),一个域名或者一个真正的服务器名字。所谓“域”,是一系列工作站和服务器的组合,它们共用一个相同的组名。
第二部分 /Mailslot 是固定的字符串。
第三部分 /[path]name,其中“path”代表路径,可指多级目录。
下面都是合法的名字:
//Oreo/Mailslot/Mymailslot
//Testserver/Mailslot/Cooldirectory/Funtest/Anothermailslot
//./Mailslot/Easymailslot
//*/Mailslot/Myslot
服务器:
1、用CreateMailslot API函数 (指定邮件槽名称) 创建一个邮件槽并获得句柄。
2、调用ReadFile API函数,使用已有的邮件槽句柄从任何客户机接收数据。
3、用CloseHandle函数关闭邮件槽句柄。
客户机:
1、使用CreateFile,针对想要向其传送数据的邮件槽(指定同一邮件槽名称为文件名),打开指向它的一个引用句柄。
2、调用WriteFile,向邮件槽写入数据。
3、完成数据写入后,用CloseHandle关闭打开的邮件槽句柄。
Code Sample:
Server Side
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
HANDLE hSlot;
LPTSTR SlotName = TEXT("\\\\.\\mailslot\\sample_mailslot");
BOOL WINAPI MakeSlot(LPTSTR lpszSlotName)
{
hSlot = CreateMailslot(lpszSlotName,
0, // no maximum message size
MAILSLOT_WAIT_FOREVER, // no time-out for operations
(LPSECURITY_ATTRIBUTES)NULL); // default security
if (hSlot == INVALID_HANDLE_VALUE)
{
printf("CreateMailslot failed with %d\n", GetLastError());
return FALSE;
}
else
printf("Mailslot created successfully.\n");
return TRUE;
}
BOOL WriteSlot(HANDLE hSlot, LPTSTR lpszMessage)
{
BOOL fResult;
DWORD cbWritten;
DWORD nNumberOfBytesToWrite = (DWORD)(lstrlen(lpszMessage) + 1)*sizeof(TCHAR);
fResult = WriteFile(hSlot,
lpszMessage,
nNumberOfBytesToWrite,
&cbWritten,
(LPOVERLAPPED)NULL);
if (!fResult)
{
printf("WriteFile failed with %d.\n", GetLastError());
return FALSE;
}
printf("Slot written to successfully.\n");
return TRUE;
}
BOOL ReadSlot()
{
DWORD cbMessage, cMessage, cbRead;
BOOL fResult;
LPTSTR lpszBuffer;
TCHAR achID[80];
DWORD cAllMessages;
HANDLE hEvent;
OVERLAPPED ov;
cbMessage = cMessage = cbRead = 0;
hEvent = CreateEvent(NULL, FALSE, FALSE, TEXT("ExampleSlot"));
if (NULL == hEvent)
return FALSE;
ov.Offset = 0;
ov.OffsetHigh = 0;
ov.hEvent = hEvent;
fResult = GetMailslotInfo(hSlot, // mailslot handle
(LPDWORD)NULL, // no maximum message size
&cbMessage, // size of next message
&cMessage, // number of messages
(LPDWORD)NULL); // no read time-out
if (!fResult)
{
printf("GetMailslotInfo failed with %d.\n", GetLastError());
return FALSE;
}
if (cbMessage == MAILSLOT_NO_MESSAGE)
{
printf("Waiting for a message...\n");
return TRUE;
}
cAllMessages = cMessage;
while (cMessage != 0) // retrieve all messages
{
// Create a message-number string.
StringCchPrintf((LPTSTR)achID,
80,
TEXT("\nMessage #%d of %d\n"),
cAllMessages - cMessage + 1,
cAllMessages);
// Allocate memory for the message.
lpszBuffer = (LPTSTR)GlobalAlloc(GPTR,
lstrlen((LPTSTR)achID)*sizeof(TCHAR)+cbMessage);
if (NULL == lpszBuffer)
return FALSE;
lpszBuffer[0] = '\0';
fResult = ReadFile(hSlot,
lpszBuffer,
cbMessage,
&cbRead,
&ov);
if (!fResult)
{
printf("ReadFile failed with %d.\n", GetLastError());
GlobalFree((HGLOBAL)lpszBuffer);
return FALSE;
}
// Concatenate the message and the message-number string.
StringCbCat(lpszBuffer,
lstrlen((LPTSTR)achID)*sizeof(TCHAR)+cbMessage,
(LPTSTR)achID);
// Display the message.
_tprintf(TEXT("Contents of the mailslot: %s\n"), lpszBuffer);
GlobalFree((HGLOBAL)lpszBuffer);
fResult = GetMailslotInfo(hSlot, // mailslot handle
(LPDWORD)NULL, // no maximum message size
&cbMessage, // size of next message
&cMessage, // number of messages
(LPDWORD)NULL); // no read time-out
if (!fResult)
{
printf("GetMailslotInfo failed (%d)\n", GetLastError());
return FALSE;
}
}
CloseHandle(hEvent);
return TRUE;
}
int _tmain(int argc, _TCHAR* argv[])
{
MakeSlot(SlotName);
Sleep(5000);
while (TRUE)
{
ReadSlot();
Sleep(3000);
}
CloseHandle(hSlot);
return 0;
}
Client Side
#include <windows.h>
#include <stdio.h>
LPTSTR SlotName = TEXT("\\\\.\\mailslot\\sample_mailslot");
BOOL WriteSlot(HANDLE hSlot, LPTSTR lpszMessage)
{
BOOL fResult;
DWORD cbWritten;
fResult = WriteFile(hSlot,
lpszMessage,
(DWORD)(lstrlen(lpszMessage) + 1)*sizeof(TCHAR),
&cbWritten,
(LPOVERLAPPED)NULL);
if (!fResult)
{
printf("WriteFile failed with %d.\n", GetLastError());
return FALSE;
}
printf("Slot written to successfully.\n");
return TRUE;
}
int main()
{
HANDLE hFile;
hFile = CreateFile(SlotName,
GENERIC_WRITE,
FILE_SHARE_READ,
(LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
(HANDLE)NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("CreateFile failed with %d.\n", GetLastError());
return FALSE;
}
WriteSlot(hFile, TEXT("Message one for mailslot."));
WriteSlot(hFile, TEXT("Message two for mailslot."));
Sleep(5000);
WriteSlot(hFile, TEXT("Message three for mailslot."));
CloseHandle(hFile);
return TRUE;
}
Output in server side:
Contents of the mailslot: Message one for mailslot.
Message #1 of 2
Message #2 of 2
Message #1 of 1
Waiting for a message...
参考:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365794(v=vs.85).aspx