《Windows核心编程》---邮槽通信
郵槽是基于廣播通信體系設計出來的,它采用無連接的不可靠UDP數據傳輸協議。使用郵槽通信的進程分為客戶端和服務端,郵槽由服務端創建,創建后,客戶端可以通過郵槽名打開郵槽,在獲得郵槽句柄后可以向郵槽寫入消息。郵槽通信是單向的,只有服務端能從郵槽中讀取消息,而客戶端只能寫入消息。消息是先進先出的。
通過郵槽通信的數據可以是任意格式的,但為了保證郵槽在各種Windows平臺下都能夠正常工作,郵槽通信一條消息的長度不能大于424字節。郵槽除了在本機上進行進程間通信外,還可以在主機之間進行通信。
實際上一個郵槽是駐留在內存中的一個Windows臨時虛擬文件,利用Windows標準文件函數可以對郵槽寫入或讀取消息,但它不同于磁盤文件的地方是:當郵槽句柄被關閉后,郵槽中的消息將被全部刪除。
?
因此,郵槽工作方式有三大特定:1)單向通信;2)廣播消息;3)數據報傳輸。
?
1)郵槽的命名:
本機上郵槽命名格式://./mailslot/[path/]name;
例如://./mailslot/win/asce_comment;
不同主機間命名格式://DomainName/mailslot/[path/]name;
??????????????????????????? //ComputerName/mailslot/[path/]name;
也可以使用通配符,以進行廣播://*/mailslot/[path/]name;
格式的說明:前兩個反斜杠之后的字符表示服務器所在機器的名稱,圓點表示是本地主機;“mailslot”是硬編碼的,這幾個字符不能改變,但大小寫無所謂。“[path/]name”當然就是郵槽名字了。
2)關鍵的API
CreateMailslot,創建一個郵槽對象:
HANDLE WINAPI CreateMailslot(
? __in????? LPCTSTR lpName, //郵槽名
? __in????? DWORD nMaxMessageSize, //單一消息最大長度,為了可以發送任意大小的消息,
//一般將該參數設置為0
? __in????? DWORD lReadTimeout, //讀超時的時間:0(如果沒有消息時立即返回);
//MAILSLOT_WAIT_FOREVER(直到讀到消息才返回)
? __in_opt? LPSECURITY_ATTRIBUTES lpSecurityAttributes //安全屬性
);
例子如下:
#include <windows.h>
#include <stdio.h>
?
HANDLE hSlot;
LPTSTR Slot = 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;
}
?
void main()
{
?? MakeSlot(Slot);
}
?
?
GetMailslotInfo,獲取指定郵槽的相關信息:
BOOL WINAPI GetMailslotInfo(
? __in?????? HANDLE hMailslot, //郵槽的句柄
? __out_opt? LPDWORD lpMaxMessageSize,???????? //返回消息的最大長度
? __out_opt? LPDWORD lpNextSize, //返回下一條消息的長度
? __out_opt? LPDWORD lpMessageCount, //返回消息的數量
? __out_opt? LPDWORD lpReadTimeout //返回讀超時時間
);
例子如下:(這個例子同時是一個完整的郵槽服務端)
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
?
HANDLE hSlot;
LPTSTR SlotName = TEXT(".//mailslot//sample_mailslot");
?
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;
}
?
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;
??? }
??? return TRUE;
}
?
void main()
{
?? MakeSlot(SlotName);
?
?? while(TRUE)
?? {
????? ReadSlot();
????? Sleep(3000);
?? }
}
?
SetMailslotInfo,修改已創建郵槽讀操作的超時時間:
BOOL WINAPI SetMailslotInfo(
? __in? HANDLE hMailslot, //郵槽句柄
? __in? DWORD lReadTimeout //新的讀超時時間
);
?
郵槽的客戶端代碼如下:
#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;
}
?
由于郵槽是基于廣播通信的,所以郵槽可以實現一對多的單向通信,例如,我們可以利用郵槽編寫一個網絡會議的通知系統。在每個被通知人電腦上安裝服務端,通知人電腦上安裝客戶端即可。
總結
以上是生活随笔為你收集整理的《Windows核心编程》---邮槽通信的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安装、部署和卸载解决方案
- 下一篇: JavaEE基础(02):Servlet