-
郵槽
鎖定
郵槽是Windows操作系統提供的一種單向進程間通信機制,可用於單機或者網絡上的多機分佈式環境。對於相對簡短的低頻率信息發送,使用郵槽通常比命名管道或Unix域套接字更簡單。如低頻率的狀態改變消息、作為對等點發現協議(peer-discovery protocol)的一部分。 郵槽機制允許短報文廣播給域上的計算機中所有監聽的進程。
- 中文名
- 郵槽
- 外文名
- MailSlot
郵槽簡介
郵槽採用的是一種比較簡單的客户/服務器體系。創建並擁有郵槽的進程為服務器,不管該進程是在主域服務器上還是在由Windows9X與NTWorkstation組成的工作站上都被視為郵槽服務器。郵槽服務器可以設置、修改郵槽的屬性,並讀取郵槽中的數據。而向指定的郵槽寫入消息的進程則為郵槽客户,同樣它不考慮郵槽所處機器在網絡上的具體身份。郵槽客户在獲得郵槽句柄之後,調用Writefile()函數將數據寫入郵槽,寫入郵槽的數據將加入到隊列中,也就是説郵槽客户可以向服務器發送任何形式的數據,但服務器不能向客户發送數據。郵槽工作方式有三大特點:
①單向通訊:創建郵槽的服務器只能讀取消息,不能寫入消息,而客户端則與之剛好相反。如果某一端應用程序要同時具備讀取與寫入的雙向功能,那麼必須在兩端的應用程序分別建立兩個郵槽;②廣播消息。假如在域上有若干計算機使用同樣的名稱創建郵槽,那麼某一郵槽客户可以一次性向所有的同名郵槽服務器發送消息;③數據報傳輸。郵槽對消息的傳輸為數據報方式,即客户端只負責數據的發送,而服務器端並不迴應客户端發送的數據是否接收到。
郵槽是一種服務器-客户接口。服務器創建郵槽,客户可以向命名的郵槽寫入內容。只有服務器可以讀取郵槽,因此郵槽是一種單向進程間通信機制。郵槽不提供報文已收到的確認,因此是不可靠通信。
郵槽應用
Windows信使服務是郵槽的最知名的應用。信使服務是一個郵槽服務器,等待報文到達後,就彈窗顯示在屏幕上。
郵槽的應用舉例:
- MAILSLOT\Messngr - 微軟NET SEND協議
- MAILSLOT\Browse - 微軟網絡鄰居共享資源瀏覽服務
- MAILSLOT\Alerter
- MAILSLOT\53cb31a0\UnimodemNotifyTSP
- MAILSLOT\HydraLsServer - Microsoft Terminal Services Licensing
- MAILSLOT\CheyenneDS -CABrightStor Discovery Service
郵槽實現
郵槽郵槽命名
郵槽的名字,從形式上看類似於文件名。格式為“\\ComputerName\mailslot\[path]name”本地郵槽名字中的ComputerName使用.來代替,即“\\.\MailSlot\路徑\文件名”。如果向當前發送計算機所在工作組或域羣發,可以使用“*”作為ComputerName。如果向指定工作組或域羣發,應使用工作組或域名作為ComputerName。本機的Windows的信使服務使用的郵槽名字是”\\.\MailSlot\ messngr“。
郵槽郵槽報文內容
郵槽報文內容包含:接收日期、發送人、接收人、具體內容。發送人、接收人、具體內容三項內容之間使用字節值0間隔。
郵槽創建郵槽
使用“CreateMailslot”創建郵槽。
郵槽寫入報文到郵槽
類似於寫入普通文件,使用“CreateFile”打開郵槽,使用“WriteFile”將內容寫入。也可以使用“NetMessageBufferSend”直接發送。
郵槽讀取郵槽報文
使用“GetMailSlotInfo”來判斷郵槽內是否有內容。發現有內容的時候,可以使用“ReadFile”讀取。如果“ReadFile”在使用MAILSLOT_WAIT_FOREVER標誌的郵槽上等待消息到來,這時郵槽突然中止運行,那麼這個應用會被永遠“掛起”直至重啓Windows系統。為此,讀郵槽的進程可以使用一個單獨線程執行讀掛起操作;主線程要結束進程時給一個全局標誌位置位,並給郵槽寫入一條消息以喚醒讀郵槽線程。“SetMailslotInfo”設置讀取郵槽的超時值。
例子:
//郵槽服務器,負責創建郵槽,讀取郵槽 #include <windows.h> #include <stdio.h> int main() { HANDLE Mailslot; char buffer[256]; DWORD NumberOfBytesRead; //Create the mailslot Mailslot = CreateMailslot("////.//Mailslot//Myslot", //指定郵槽的名字 0, //可寫入郵槽的消息的最大字節長度;為0表示接收任意長度消息 MAILSLOT_WAIT_FOREVER, //等待或不等待,單位毫秒,MAILSLOT_WAIT_FOREVER無限期等待,0立即返回 NULL); //訪問控制權限,一般為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; }
//郵槽客户端,用於發送數據到郵槽服務器 #include <windows.h> #include <stdio.h> int main(int argc, char *argv[]) { HANDLE Mailslot; DWORD BytesWritten; CHAR ServerName[256]; //從命令行接受要發送數據到的服務器名 if (argc < 2) { printf("Usage: client <server name>/n"); return -1; } sprintf(ServerName, "////%s//Mailslot//Myslot",argv[1]); Mailslot = CreateFile(ServerName, //郵槽名字 GENERIC_WRITE, //必須為GENERIC_WRITE,因為客户端只能向郵槽寫入數據 FILE_SHARE_READ, /必須為FILE_SHARE_READ,因為郵槽服務器需要做打開和讀操作 NULL, OPEN_EXISTING, //郵槽在本地且還沒有創建郵槽則當前調用失敗;郵槽在遠程,該參數無意義 FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == Mailslot) { printf("WriteFile failed with error %d/n",GetLastError()); return -1; } if(0 == WriteFile(Mailslot, "This is a test", 14, &BytesWritten,NULL)) { printf("WriteFile failed with error %d/n", GetLastError()); return -1; } printf("Wrote %d byteds/n", BytesWritten); CloseHandle(Mailslot); return 0; }
郵槽使用郵槽注意的問題
開發郵槽客户機和服務器應用時,所有Win32API函數(CreateFile和CreateMailslot除外)在調用失敗的情況下,都會返回0值。CreateFile和CreateMailslot這兩個API卻會返回INVALIDHANDLEVALUE(無效句柄值)。若這些API函數調用失敗,應用程序隨即應調用GetLastError函數,來接收與此次失敗有關的特殊信息。
對於Windows95和Windows98來説,值得注意的最後一個問題便是內存空間的“廢棄”,或者説內存空間產生了“漏洞”。在郵槽上使用超時設定時,便有可能出現這一現象。假如用CreateMailslot函數創建一個郵槽,同時將超時時間設為大於0的一個值,那麼一旦超過這一時間,ReadFile函數便會造成內存空間的廢棄,生成所謂的“內存漏洞”。同時,函數會返回FALSE。經過多次ReadFile函數調用之後,系統就會變得極不穩定,以後超時的ReadFile調用會開始返回TRUE。因此,系統不能再執行其他MS-DOS程序。為解決這個問題,請將超時值設為0或者MAILSLOTWAITFOREVER。這樣便可禁止應用程序使用超時機制,從而避免了實際產生的內存“漏洞”。
- 參考資料
-
- 1. 基於Windows的郵槽機制的研究 .中國知網[引用日期2018-06-28]