进程间通讯总结 (3)

本文介绍如何通过邮件槽(mailslot)实现Windows环境下进程间的简单消息传递。邮件槽是一种临时存储消息的一次性通信机制,支持本地及跨计算机的消息广播。文章详细解释了邮件槽的创建过程、消息读写操作,并提供了服务器端与客户端的应用实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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:

Mailslot created successfully.
Contents of the mailslot: Message one for mailslot.
Message #1 of 2

Contents of the mailslot: Message two for mailslot.
Message #2 of 2

Contents of the mailslot: Message three for mailslot.
Message #1 of 1

Waiting for a message...
Waiting for a message...


参考:

https://msdn.microsoft.com/en-us/library/windows/desktop/aa365794(v=vs.85).aspx


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值