郵槽是Windows操作系統(tǒng)提供的一種單向進(jìn)程間通信機(jī)制,可用于單機(jī)或者網(wǎng)絡(luò)上的多機(jī)分布式環(huán)境。對(duì)于相對(duì)簡(jiǎn)短的低頻率信息發(fā)送,使用郵槽通常比命名管道或Unix域套接字更簡(jiǎn)單。如低頻率的狀態(tài)改變消息、作為對(duì)等點(diǎn)發(fā)現(xiàn)協(xié)議(peer-discovery protocol)的一部分。 郵槽機(jī)制允許短報(bào)文廣播給域上的計(jì)算機(jī)中所有監(jiān)聽的進(jìn)程。
簡(jiǎn)介郵槽采用的是一種比較簡(jiǎn)單的客戶/服務(wù)器體系。創(chuàng)建并擁有郵槽的進(jìn)程為服務(wù)器,不管該進(jìn)程是在主域服務(wù)器上還是在由Windows9X與NTWorkstation組成的工作站上都被視為郵槽服務(wù)器。郵槽服務(wù)器可以設(shè)置、修改郵槽的屬性,并讀取郵槽中的數(shù)據(jù)。而向指定的郵槽寫入消息的進(jìn)程則為郵槽客戶,同樣它不考慮郵槽所處機(jī)器在網(wǎng)絡(luò)上的具體身份。郵槽客戶在獲得郵槽句柄之后,調(diào)用Writefile()函數(shù)將數(shù)據(jù)寫入郵槽,寫入郵槽的數(shù)據(jù)將加入到隊(duì)列中,也就是說(shuō)郵槽客戶可以向服務(wù)器發(fā)送任何形式的數(shù)據(jù),但服務(wù)器不能向客戶發(fā)送數(shù)據(jù)。郵槽工作方式有三大特點(diǎn):
①單向通訊:創(chuàng)建郵槽的服務(wù)器只能讀取消息,不能寫入消息,而客戶端則與之剛好相反。如果某一端應(yīng)用程序要同時(shí)具備讀取與寫入的雙向功能,那么必須在兩端的應(yīng)用程序分別建立兩個(gè)郵槽;②廣播消息。假如在域上有若干計(jì)算機(jī)使用同樣的名稱創(chuàng)建郵槽,那么某一郵槽客戶可以一次性向所有的同名郵槽服務(wù)器發(fā)送消息;③數(shù)據(jù)報(bào)傳輸。郵槽對(duì)消息的傳輸為數(shù)據(jù)報(bào)方式,即客戶端只負(fù)責(zé)數(shù)據(jù)的發(fā)送,而服務(wù)器端并不回應(yīng)客戶端發(fā)送的數(shù)據(jù)是否接收到。
郵槽是一種服務(wù)器-客戶接口。服務(wù)器創(chuàng)建郵槽,客戶可以向命名的郵槽寫入內(nèi)容。只有服務(wù)器可以讀取郵槽,因此郵槽是一種單向進(jìn)程間通信機(jī)制。郵槽不提供報(bào)文已收到的確認(rèn),因此是不可靠通信。
郵槽基于RPC協(xié)議,可以在同一個(gè)網(wǎng)絡(luò)域上跨計(jì)算機(jī)使用。1
應(yīng)用Windows信使服務(wù)是郵槽的最知名的應(yīng)用。信使服務(wù)是一個(gè)郵槽服務(wù)器,等待報(bào)文到達(dá)后,就彈窗顯示在屏幕上。
郵槽的應(yīng)用舉例:
MAILSLOT\Messngr - 微軟NET SEND協(xié)議
MAILSLOT\Browse - 微軟網(wǎng)絡(luò)鄰居共享資源瀏覽服務(wù)
MAILSLOT\Alerter
MAILSLOT\53cb31a0\UnimodemNotifyTSP
MAILSLOT\HydraLsServer - Microsoft Terminal Services Licensing
MAILSLOT\CheyenneDS -CABrightStor Discovery Service
實(shí)現(xiàn)郵槽命名郵槽的名字,從形式上看類似于文件名。格式為“\\ComputerName\mailslot\[path]name”本地郵槽名字中的ComputerName使用.來(lái)代替,即“\\.\MailSlot\路徑\文件名”。如果向當(dāng)前發(fā)送計(jì)算機(jī)所在工作組或域群發(fā),可以使用“*”作為ComputerName。如果向指定工作組或域群發(fā),應(yīng)使用工作組或域名作為ComputerName。本機(jī)的Windows的信使服務(wù)使用的郵槽名字是”\\.\MailSlot\ messngr“。
郵槽報(bào)文內(nèi)容郵槽報(bào)文內(nèi)容包含:接收日期、發(fā)送人、接收人、具體內(nèi)容。發(fā)送人、接收人、具體內(nèi)容三項(xiàng)內(nèi)容之間使用字節(jié)值0間隔。
創(chuàng)建郵槽使用“CreateMailslot”創(chuàng)建郵槽。
寫入報(bào)文到郵槽類似于寫入普通文件,使用“CreateFile”打開郵槽,使用“WriteFile”將內(nèi)容寫入。也可以使用“NetMessageBufferSend”直接發(fā)送。
讀取郵槽報(bào)文使用“GetMailSlotInfo”來(lái)判斷郵槽內(nèi)是否有內(nèi)容。發(fā)現(xiàn)有內(nèi)容的時(shí)候,可以使用“ReadFile”讀取。如果“ReadFile”在使用MAILSLOT_WAIT_FOREVER標(biāo)志的郵槽上等待消息到來(lái),這時(shí)郵槽突然中止運(yùn)行,那么這個(gè)應(yīng)用會(huì)被永遠(yuǎn)“掛起”直至重啟Windows系統(tǒng)。為此,讀郵槽的進(jìn)程可以使用一個(gè)單獨(dú)線程執(zhí)行讀掛起操作;主線程要結(jié)束進(jìn)程時(shí)給一個(gè)全局標(biāo)志位置位,并給郵槽寫入一條消息以喚醒讀郵槽線程?!癝etMailslotInfo”設(shè)置讀取郵槽的超時(shí)值。
例子:
//郵槽服務(wù)器,負(fù)責(zé)創(chuàng)建郵槽,讀取郵槽#include #include int main(){ HANDLE Mailslot; char buffer[256]; DWORD NumberOfBytesRead; //Create the mailslot Mailslot = CreateMailslot("////.//Mailslot//Myslot", //指定郵槽的名字 0, //可寫入郵槽的消息的最大字節(jié)長(zhǎng)度;為0表示接收任意長(zhǎng)度消息 MAILSLOT_WAIT_FOREVER, //等待或不等待,單位毫秒,MAILSLOT_WAIT_FOREVER無(wú)限期等待,0立即返回 NULL); //訪問(wèn)控制權(quán)限,一般為NULL if (INVALID_HANDLE_VALUE == Mailslot) { printf("Failed to create a mailslot %d/n", GetLastError()); return -1; } //Read data from the mailslot forever! while (0 != ReadFile(Mailslot, buffer, 256, &NumberOfBytesRead, NULL)) { printf("%.*s/n",NumberOfBytesRead,buffer); } CloseHandle(Mailslot); return 0;}//郵槽客戶端,用于發(fā)送數(shù)據(jù)到郵槽服務(wù)器#include #include int main(int argc, char *argv[]){ HANDLE Mailslot; DWORD BytesWritten; CHAR ServerName[256]; //從命令行接受要發(fā)送數(shù)據(jù)到的服務(wù)器名 if (argc