利用邮槽(mailslot)进行应用程序间的通讯实例

在两个不同的应用程序之间可能需要传递数据,利用邮槽(mailslot)可以达成目标,一个程序(客户端)向邮槽写数据,另一个程序(服务端)负责接收数据。(为了保证在UNICODE与ANSI的通用,程序使用了tchar.h头文件,并尽可能使用通用类型TCHAR与相应的通用函数)

一、Demo代码(两个独立的应用程序,客户端发送倒计时数字)

server端:

#include<Windows.h>
#include<stdio.h>
#include<tchar.h>
	HANDLE hSlot;
	//邮路路径
	LPCTSTR lpszSlotName = _TEXT("\\\\.\\mailslot\\sample_mailslot");
	_TCHAR lpszBuffer[1000];                       //接收缓冲区
	_TCHAR prompting_message[80];                  //用作提示信息
	DWORD cbMessage, cMessage, cbRead, cAllMessages;
	BOOL bResult;
void main() {
			
	cbMessage = cMessage = cbRead = 0;
	hSlot = CreateMailslot(lpszSlotName, 0, MAILSLOT_WAIT_FOREVER, (LPSECURITY_ATTRIBUTES)NULL);
	if (hSlot == INVALID_HANDLE_VALUE)
	{
		//创建失败
		printf("CreateMailslot failed with %d\n", GetLastError());
		return;
	}
	else 
	{
		//创建成功
		printf("创建成功\n!");
	}
	while (1) {
		bResult = GetMailslotInfo(hSlot, // mailslot 句柄 
			(LPDWORD)NULL,               // 无最大消息限制
			&cbMessage,                  // 下一条消息的大小
			&cMessage,                   // 消息的数量
			(LPDWORD)NULL);              // 无时限
		
		if (!bResult)
		{
			printf("GetMailslotInfo failed with %d.\n", GetLastError());
			return;
		}
		
		if (cbMessage == MAILSLOT_NO_MESSAGE)
		{
			printf("没有邮槽消息 \n");
			// 没有消息,过一段时间再去读
			Sleep(3000);
			continue;
		}
		printf("收到邮槽消息\n");
		cAllMessages = cMessage;
		while (cMessage != 0)  // 获取全部消息,有可能不只一条
		{
			// 提示信息
			_stprintf_s(prompting_message, _TEXT("      (%d/%d)\n"), cAllMessages - cMessage + 1, cAllMessages);
			// 读取消息 
			if (!ReadFile(hSlot, (LPVOID)lpszBuffer, cbMessage, &cbRead, NULL))
			{
				printf("ReadFile failed with %d.\n", GetLastError());
				return;
			}
			_tcscat_s(lpszBuffer, prompting_message); //连接
			_tprintf(_TEXT("message: %s\n"), lpszBuffer);//显示		
			
			bResult = GetMailslotInfo(hSlot, NULL, &cbMessage, &cMessage, NULL); // 计算剩余的消息数,若cMessage=0,则退出子循环
			if (!bResult)
			{
				printf("GetMailslotInfo failed (%d)\n", GetLastError());
				return;
			}
		}
	}
}

client端:

#include <windows.h> 
#include <stdio.h> 
#include<tchar.h>

LPTSTR lpszSlotName = _TEXT("\\\\.\\mailslot\\sample_mailslot");		// mailslot名
_TCHAR lpszMessage[1000];											    // 通信的内容
void main()
{
	//成功写入的字节数
	DWORD cbWritten;

	// 打开mailslot
	HANDLE hFile = CreateFile(lpszSlotName,
		GENERIC_WRITE,		// 可写
		FILE_SHARE_READ,
		(LPSECURITY_ATTRIBUTES)NULL,
		OPEN_EXISTING,		// 打开一个已经存在的mailslot,应该由服务端已经创建
		FILE_ATTRIBUTE_NORMAL,
		(HANDLE)NULL);
	if (hFile == INVALID_HANDLE_VALUE)//打开失败
	{
		printf("CreateFile failed with %d.\n", GetLastError());
		return;
	}
	// 向mailslot写入
	int num = 50;
	printf("本编译环境下_TCHAR所占字节数:%dbyte\n", sizeof(_TCHAR));
	while (num)
	{
		Sleep(2000);
		num--;
		_stprintf_s(lpszMessage, _TEXT("number %d"), num);
		if (!WriteFile(hFile,(LPCVOID)lpszMessage,(DWORD)(sizeof(_TCHAR)*_tcslen(lpszMessage) + 1),&cbWritten,(LPOVERLAPPED)NULL))
		{
			printf("WriteFile failed with %d.\n", GetLastError());
			return;
		}
		printf("发送成功,发送字节数:%dbyte\n",_tcslen(lpszMessage));
	}
	CloseHandle(hFile);  // 结束 
}

运行截图,UNICODE编码下

server端:

client端:

在ANSI编码下运行

server端:

client端:

二、关键函数(可结和Demo)

1、CreateMailslot 创建具有指定名称的邮件槽,并返回邮件槽服务器可用于对邮件槽执         行操作的句柄

HANDLE CreateMailslotA(
  LPCSTR                lpName,
  DWORD                 nMaxMessageSize,
  DWORD                 lReadTimeout,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes
);
  • 参数:
  1. lpName                                 邮箱的名称。此名称必须具有以下形式:\.\mailslot[path]name
  2. nMaxMessageSize              可以写入邮件槽的单个消息的最大大小(以字节为单位)
  3. lReadTimeout                      读取操作可以等待在超时发生之前将消息写入邮件槽的时间(以毫秒为单位)
  4. lpSecurityAttributes             指向SECURITY ATTRIBUTES结构的指针 
  • 返回值如果函数成功,则返回值是邮件槽的句柄,用于服务器邮件槽操作。此函数返回的句柄是异步的,或重叠的。 如果函数失败,则返回值为INVALID_HANDLE_VALUE

2、GetMailslotInfo 检索有关指定邮件槽的信息

BOOL GetMailslotInfo(
  HANDLE  hMailslot,
  LPDWORD lpMaxMessageSize,
  LPDWORD lpNextSize,
  LPDWORD lpMessageCount,
  LPDWORD lpReadTimeout
);
  • 参数:
  1. hMailslot                               邮件的句柄。
  2. lpMaxMessageSize             此邮件槽允许的最大邮件大小(以字节为单位),此参数可以为NULL
  3. lpNextSize                             下一条消息的大小,以字节为单位。MAILSLOT_NO_MESSAGE 表示没有下一条消息
  4. lpMessageCount                 函数返回时等待读取的消息总数。   
  5. lpReadTimeout                    读取操作可以等待在超时发生之前将消息写入邮件槽的时间量(以毫秒为单位)。函数返回                                                    时填充此参数,此参数可以为NULL
  • 返回值:如果函数成功,则返回值为非零值。 如果函数失败,则返回值为零。要获取扩展错误信息,请调用GetLastError();

3、ReadFile 从指定文件或输入/输出(I / O)设备读取数据

BOOL ReadFile(
  HANDLE       hFile,
  LPVOID       lpBuffer,
  DWORD        nNumberOfBytesToRead,
  LPDWORD      lpNumberOfBytesRead,
  LPOVERLAPPED lpOverlapped
);
  • 参数:
  1. hFile                                                               设备的句柄(例如,文件,文件流,物理磁盘,卷,控制台缓冲区,磁带驱动                                                                              器,套接字,通信资源,邮件槽或管道)。
  2. lpBuffer                                                          指向缓冲区的指针,该缓冲区接收从文件或设备读取的数据。
  3. nNumberOfBytesToRead                          要读取的最大字节数。
  4. lpNumberOfBytesRead                              指向变量的指针,该变量接收使用同步hFile参数时读取的字节 数。
  5. lpOverlapped                                                如果使用FILE_FLAG_OVERLAPPED打开hFile参数, 则需要指向                                                                                                  OVERLAPPED结构的指针,否则它可以为NULL。  
  • 返回值:如果函数成功,则返回值为非零(TRUE)。如果函数失败或异步完成,则返回值为零(FALSE),要获取扩展错误信息,请调用GetLastError();

4、CreateFile 创建或打开文件或I / O设备

HANDLE CreateFileA(
  LPCSTR                lpFileName,
  DWORD                 dwDesiredAccess,
  DWORD                 dwShareMode,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  DWORD                 dwCreationDisposition,
  DWORD                 dwFlagsAndAttributes,
  HANDLE                hTemplateFile
);
  • 参数:
  1. lpFileName                                要创建或打开的文件或设备的名称。
  2. dwDesiredAccess                    请求访问文件或设备,可以概括为读,写,两者或两者都不为零。
  3. dwShareMode                           请求的文件或设备共享模式,可以是读取,写入,同时,删除,所有这些或无。
  4. lpSecurityAttributes                   指向SECURITY ATTRIBUTES 结构的指针,此参数可以为NULL
  5. dwCreationDisposition           对存在或不存在的文件或设备执行的操作。对于文件以外的设备,常设置为                                                                                 OPEN_EXISTING
  6. dwFlagsAndAttributes              文件或设备属性和标志,FILE_ATTRIBUTE_NORMAL是文件的最常见默认值。
  7. hTemplateFile                           具有GENERIC_READ访问权限的模板文件的有效句柄。此参数可以为NULL
  • 返回值:如果函数成功,则返回值是指定文件,设备,命名管道或邮件槽的打开句柄。 如果函数失败,则返回值为INVALID_HANDLE_VALUE

5、WriteFile 将数据写入指定的文件或输入/输出(I / O)设备。

BOOL WriteFile(
  HANDLE       hFile,
  LPCVOID      lpBuffer,
  DWORD        nNumberOfBytesToWrite,
  LPDWORD      lpNumberOfBytesWritten,
  LPOVERLAPPED lpOverlapped
);
  • 参数:
  1. hFile                                             文件或I / O设备的句柄。
  2. lpBuffer                                        指向包含要写入文件或设备的数据的缓冲区的指针。
  3. nNumberOfBytesToWrite         要写入文件或设备的字节数。
  4. lpNumberOfBytesWritten         指向变量的指针,该变量接收使用同步hFile参数时写入的字节 数。
  5. lpOverlapped                              如果使用FILE_FLAG_OVERLAPPED打开hFile参数, 则需要指向OVERLAPPED结构的指                                                        针,否则此参数可以为NULL
  • 返回值:如果函数成功,则返回值为非零(TRUE)。如果函数失败或异步完成,则返回值为零(FALSE),要获取扩展错误信息,请调用GetLastError();

三、关于通用字符

如何编写符合ANSI和Unicode的应用程序?
(1) 将文本串视为字符数组,而不是chars数组或字节数组。
(2) 将通用数据类型(如TCHAR和PTSTR)用于文本字符和字符串。
(3) 将显式数据类型(如BYTE和PBYTE)用于字节、字节指针和数据缓存。
(4) 将TEXT宏用于原义字符和字符串。
(5) 执行全局性替换(例如用PTSTR替换PSTR)。
(6) 修改字符串运算问题。例如函数通常希望在字符中传递一个缓存的大小,而不是字节。这意味着不应该传递                                   sizeof(szBuffer),而应该传递(sizeof(szBuffer)/sizeof(TCHAR)。另外,如果需要为字符串分配一个内存块,并且拥有该               字符串中的字符数目,那幺请记住要按字节来分配内存。这就是说,应该调用malloc(nCharacters *sizeof(TCHAR)),而               不是调用malloc(nCharacters)。

关于tchar.h

https://blog.csdn.net/u013407116/article/details/78107868

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值