在Windows环境下,实现进程间通信的方式有很多种,如套接字、管道、远程过程调用和NETBIOS等,邮槽是其中实现单通道进程间通信的一种。创建邮槽的进程被称为邮槽服务器,而其它发送消息给邮槽的进程被称为邮槽客户端。邮槽客户端能发送消息给本机的邮槽,也可发送消息给局域网内其他计算机内的邮槽,所有这些消息都存储在邮槽内,直到邮槽服务器读取它。这些消息通常是以广播的方式发送,建立在面向无链接的数据报的基础上,因此在线路不好时传输质量不可靠。
这种进程间通信的方式比较适用于在局域网环境内传送和接收短消息,也可在局域网内向所有计算机广播消息。
用邮槽进行进程间通信主要通过三个步骤来实现:创建邮槽服务器,向邮槽发送消息和从邮槽中读取消息。下面将用Windows的API函数来完成这三个步骤。
邮槽的客户端代码实现如下。
/* 头文件 */ #include <windows.h> #include <stdio.h> /* 全局变量 */ HANDLE hSlot; LPTSTR lpszSlotName = TEXT("\\\\.\\mailslot\\sample_mailslot"); // mailslot名 LPTSTR lpszMessage = TEXT("Test Message for mailslot "); // 通信的内容 /* ************************************ * void main() * 功能 进程间mailslot通信客户端 **************************************/ void main() { BOOL fResult; HANDLE hFile; DWORD cbWritten; DWORD cbMessage; // 打开mailslot 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写入 fResult = WriteFile(hFile, lpszMessage, (DWORD) (lstrlen(lpszMessage)+1)*sizeof(TCHAR), &cbWritten, (LPOVERLAPPED) NULL); if (!fResult) { printf("WriteFile failed with %d.\n", GetLastError()); return ; } // 结束 printf("Slot written to successfully.\n"); CloseHandle(hFile); return ; }
邮槽的服务端代码实现如下。
/* 头文件 */ #include <windows.h> #include <stdio.h> /* 全局变量 */ HANDLE hSlot; LPTSTR lpszSlotName = TEXT("\\\\.\\mailslot\\sample_mailslot"); LPTSTR Message = TEXT("Message for mailslot in primary domain."); /* ************************************ * void main() * 功能 进程间mailslot通信客户端 **************************************/ void main() { DWORD cbMessage, cMessage, cbRead; BOOL fResult; LPTSTR lpszBuffer; TCHAR achID[80]; DWORD cAllMessages; HANDLE hEvent; OVERLAPPED ov; cbMessage = cMessage = cbRead = 0; hSlot = CreateMailslot( lpszSlotName, // mailslot 名 0, // 不限制消息大小 MAILSLOT_WAIT_FOREVER, // 无超时 (LPSECURITY_ATTRIBUTES) NULL); if (hSlot == INVALID_HANDLE_VALUE) { printf("CreateMailslot failed with %d\n", GetLastError()); return ; } else printf("Mailslot created successfully.\n"); while(1) { // 获取mailslot信息 fResult = GetMailslotInfo(hSlot, // mailslot 句柄 (LPDWORD) NULL, // 无最大消息限制 &cbMessage, // 下一条消息的大小 &cMessage, // 消息的数量 (LPDWORD) NULL); // 无时限 if (!fResult) { printf("GetMailslotInfo failed with %d.\n", GetLastError()); return ; } if (cbMessage == MAILSLOT_NO_MESSAGE) { // 没有消息,过一段时间再去读 Sleep(20000); continue; } cAllMessages = cMessage; while (cMessage != 0) // 获取全部消息,有可能不只一条 { // 提示信息 wsprintf((LPTSTR) achID, "\nMessage #%d of %d\n", cAllMessages - cMessage + 1, cAllMessages); // 分配空间 lpszBuffer = (LPTSTR) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, lstrlen((LPTSTR) achID)*sizeof(TCHAR) + cbMessage); if( NULL == lpszBuffer ) { return ; } // 读取消息 fResult = ReadFile(hSlot, // mailslot句柄 lpszBuffer, // 缓存 cbMessage, // 消息的长度 &cbRead, // 实际读取的长度 NULL); if (!fResult) { printf("ReadFile failed with %d.\n", GetLastError()); GlobalFree((HGLOBAL) lpszBuffer); return ; } // 处理信息,显示 lstrcat(lpszBuffer, (LPTSTR) achID); printf("Contents of the mailslot: %s\n", lpszBuffer); HeapFree(GetProcessHeap(),0,lpszBuffer); // 计算剩余的消息数 fResult = GetMailslotInfo(hSlot, (LPDWORD) NULL, &cbMessage, &cMessage, (LPDWORD) NULL); if (!fResult) { printf("GetMailslotInfo failed (%d)\n", GetLastError()); return ; } } } return ; }
/* 头文件 */ #include <windows.h> #include <stdio.h> /* 全局变量 */ HANDLE hSlot; LPTSTR lpszSlotName = TEXT("\\\\.\\mailslot\\sample_mailslot"); LPTSTR Message = TEXT("Message for mailslot in primary domain."); /* ************************************ * void main() * 功能 进程间mailslot通信客户端 **************************************/ void main() { DWORD cbMessage, cMessage, cbRead; BOOL fResult; LPTSTR lpszBuffer; TCHAR achID[80]; DWORD cAllMessages; HANDLE hEvent; OVERLAPPED ov; cbMessage = cMessage = cbRead = 0; hSlot = CreateMailslot( lpszSlotName, // mailslot 名 0, // 不限制消息大小 MAILSLOT_WAIT_FOREVER, // 无超时 (LPSECURITY_ATTRIBUTES) NULL); if (hSlot == INVALID_HANDLE_VALUE) { printf("CreateMailslot failed with %d\n", GetLastError()); return ; } else printf("Mailslot created successfully.\n"); while(1) { // 获取mailslot信息 fResult = GetMailslotInfo(hSlot, // mailslot 句柄 (LPDWORD) NULL, // 无最大消息限制 &cbMessage, // 下一条消息的大小 &cMessage, // 消息的数量 (LPDWORD) NULL); // 无时限 if (!fResult) { printf("GetMailslotInfo failed with %d.\n", GetLastError()); return ; } if (cbMessage == MAILSLOT_NO_MESSAGE) { // 没有消息,过一段时间再去读 Sleep(20000); continue; } cAllMessages = cMessage; while (cMessage != 0) // 获取全部消息,有可能不只一条 { // 提示信息 wsprintf((LPTSTR) achID, "\nMessage #%d of %d\n", cAllMessages - cMessage + 1, cAllMessages); // 分配空间 lpszBuffer = (LPTSTR) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, lstrlen((LPTSTR) achID)*sizeof(TCHAR) + cbMessage); if( NULL == lpszBuffer ) { return ; } // 读取消息 fResult = ReadFile(hSlot, // mailslot句柄 lpszBuffer, // 缓存 cbMessage, // 消息的长度 &cbRead, // 实际读取的长度 NULL); if (!fResult) { printf("ReadFile failed with %d.\n", GetLastError()); GlobalFree((HGLOBAL) lpszBuffer); return ; } // 处理信息,显示 lstrcat(lpszBuffer, (LPTSTR) achID); printf("Contents of the mailslot: %s\n", lpszBuffer); HeapFree(GetProcessHeap(),0,lpszBuffer); // 计算剩余的消息数 fResult = GetMailslotInfo(hSlot, (LPDWORD) NULL, &cbMessage, &cMessage, (LPDWORD) NULL); if (!fResult) { printf("GetMailslotInfo failed (%d)\n", GetLastError()); return ; } } } return ; }