【轉】Windows 郵件槽(MailSlot)

來源:互聯網
上載者:User

標籤:

Windows 郵件槽(MailSlot) 來自《Windows網路編程第二版 中文版》 優點:通過網路,將一條訊息廣播給一台或多台電腦。  缺點:只允許從客戶機到伺服器,建立一種不可靠的單向資料通訊。不提供資料可靠性傳播的保障。 郵件槽是圍繞Windows檔案系統介面設計出來的。客戶機和伺服器應用需要使用標準的Win32檔案系統I/O函數,如ReadFile和WriteFile等,以便在郵件槽上收發資料,同時利用Win32檔案系統的命名規則。  郵件槽的名字郵件槽標識遵守下述命名規則://server/Mailslot/[path]name第一部分//server對應伺服器名,在其上建立郵件槽並在上面運行伺服器程式。取值可以是小數點(.),一個星號(*),一個網域名稱或者一個真正的伺服器名字。所謂“域”,是一系列工作站和伺服器的組合,它們共用一個相同的組名。第二部分/Mailslot是固定的字串。第三部分/[path]name,其中“path”代表路徑,可指多級目錄。下面都是合法的名字://Oreo/Mailslot/Mymailslot//Testserver/Mailslot/Cooldirectory/Funtest/Anothermailslot//./Mailslot/Easymailslot//*/Mailslot/Myslot  訊息的長度郵件槽常用“無串連”形式發送“資料報”(Datagram),不要求對方提供包的收到確認資訊。通過無串連可將訊息從一個客戶機廣播給多個伺服器。例外:在Windows NT和Windows 2000中,假如訊息長度超過424個位元組,必須使用“連線導向”的協議進行傳輸,而不再使用不需連線的“資料報”形式。這樣也就不能將一條訊息從客戶機廣播給多個伺服器。對於“連線導向”的傳輸來說,必然是“一對一”通訊:一個客戶機對一個伺服器。  應用程式的編譯用VC++ 6.0編製郵件槽應用程式時,必須包含Winbase.h標頭檔。如果已經包含Windows.h就可省去Winbase.h。應用程式需要與Kernel32.lib連結(是VC++ 6.0預設配置)。  錯誤碼郵件槽應用開發中,所有Win32 API函數(CreateFile和CreateMailslot除外)在調用失敗時都返回0。CreateFile和CreateMailslot這兩個API返回INVALID_HANDLE_VALUE(無效控制代碼值)。調用失敗可以使用GetLastError函數接受與此次失敗相關的特殊資訊。  基本客戶機/伺服器伺服器處理序:建立一個郵件槽,能從該郵件槽讀資料的唯一一個進程。客戶機:負責開啟郵件槽“執行個體”,是能向其中寫入資料的唯一一種進程。 伺服器:1、用CreateMailslot API函數建立一個郵件槽並獲得控制代碼。2、調用ReadFile API函數,使用已有的郵件槽控制代碼從任何客戶機接收資料。3、用CloseHandle函數關閉郵件槽控制代碼。建立郵件槽:HANDLE CreateMailslot(LPCTSTR lpName, //指定郵件槽的名字,如//./Mailslot/[path]name,小數點表示伺服器為本的機器(不能為遠端電腦建立郵件槽)。DWORD nMaxMessageSize,//可寫入郵件槽的最大訊息長度(位元組單位),客戶機發生訊息大於該值伺服器不接受該訊息;為0,接收任意長度訊息。DWORD lReadTiemout,//等待模式和不等待模式,MAILSLOT_WAIT_FOREVER無限期等待,0立即返回,其它值以毫秒為單位。LPSECURITY_ATTRIBUTES lpSecurityAttributes//存取控制許可權,一般都這位NULL);讀取郵件槽中資料:BOOL ReadFile(HANDLE hFile,//CreateMailslot返回的郵件槽控制代碼LPVOID lpBuffer,//和nNumberOfBytesToRead一起決定可從郵件槽讀入多少資料;應比CreateMailslot中的nMaxMessageSize。DWORD nNumberOfBytesToRead,//如果不夠大,ReadFile調用失敗返回ERROR_INSUFFICIENT_BUFFER錯誤。LPWORD lpNumberOfBytesRead,//讀取完成後報告讀入的實際位元組數。LPOVERLAPPED lpOverlapped//可採用Win32重疊I/O機制;不採用就設為NULL,調用後阻塞直到有資料讀入。);
  1. //Server.cpp
  2. //伺服器郵件槽,用於接收客戶發送的廣播資訊
  3. #include <windows.h>
  4. #include <stdio.h>
  5. int main()
  6. {
  7.  HANDLE Mailslot;
  8.  char buffer[256];
  9.  DWORD NumberOfBytesRead;
  10.  //Create the mailslot
  11.  Mailslot = CreateMailslot("////.//Mailslot//Myslot",0,
  12.   MAILSLOT_WAIT_FOREVER,NULL);
  13.  if (INVALID_HANDLE_VALUE == Mailslot)
  14.  {
  15.   printf("Failed to create a mailslot %d/n", GetLastError());
  16.   return -1;
  17.  }
  18.  //Read data from the mailslot forever!
  19.  while (0 != ReadFile(Mailslot, buffer, 256, &NumberOfBytesRead, NULL))
  20.  {
  21.   printf("%.*s/n",NumberOfBytesRead,buffer);
  22.  }
  23.  CloseHandle(Mailslot);
  24.  return 0;
  25. }
客戶機:對一個現有的郵件槽進行引用和寫入。1、使用CreateFile,針對想要向其傳送資料的郵件槽,開啟指向它的一個引用控制代碼。2、調用WriteFile,向郵件槽寫入資料。3、完成資料寫入後,用CloseHandle關閉開啟的郵件槽控制代碼。開啟指向郵件槽的一個引用控制代碼:HANDLE CreateFile(LPCTSTR lpFileName,//郵件槽名字DWORD dwDesiredAccess,//必須為GENERIC_WRITE,因為客戶機只能向伺服器寫入資料。DWORD dwSharedMode,//必須為FILE_SHARE_READ,運行伺服器在郵件槽開啟和進行讀操作。LPSECURITY_ATTRIBUTES lpSecurityAttributes,//設為NULL。DWORD dwCreationDisposition,//設為OPEN_EXISTING,伺服器是本地且沒有建立郵件槽調用會失敗;伺服器在遠程,該參數無意義。DWORD dwFlagsAndAttributes,//設為FILE_ATTRIBUTE_NORMALHANDLE hTemplateFile//設為NULL);寫入資料:BOOL WriteFile(HANDLE hFile,//CreateFile返回的引用控制代碼LPCVOID lpBuffer,//發送的字串DWORD nNumberOfBytesToWrite,//發送的字串長度(一條最大長度為64KB)。LPDWORD lpNumberOfBytesWritten,//操作完成後實際發送的資料位元組數。LPOVERLAPPED lpOverlapped//郵件槽是“無串連”資料轉送,WriteFile函數在不會在I/O調用時等候,所以參數設為NULL  
  1. //Client.cpp
  2. //用戶端用於發送廣播資料到伺服器
  3. #include <windows.h>
  4. #include <stdio.h>
  5. int main(int argc, char *argv[])
  6. {
  7.     HANDLE Mailslot;
  8.     DWORD BytesWritten;
  9.     CHAR ServerName[256];
  10.     //從命令列接受要發送資料到的伺服器名
  11.     if (argc < 2)
  12.     {
  13.         printf("Usage: client <server name>/n");
  14.         return -1;
  15.     }
  16.     sprintf(ServerName, "////%s//Mailslot//Myslot",argv[1]);
  17.     Mailslot = CreateFile(ServerName, GENERIC_WRITE,
  18.         FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);
  19.     if (INVALID_HANDLE_VALUE == Mailslot)
  20.     {
  21.         printf("WriteFile failed with error %d/n",GetLastError());
  22.         return -1;
  23.     }
  24.     if(0 == WriteFile(Mailslot, "This is a test", 14, &BytesWritten,NULL))
  25.     {
  26.         printf("WriteFile failed with error %d/n", GetLastError());
  27.         return -1;
  28.     }
  29.     printf("Wrote %d byteds/n", BytesWritten);
  30.     CloseHandle(Mailslot);
  31.     return 0;
  32. }
伺服器其它APIGetMailslotInfo:一旦郵件槽上有訊息可以傳遞,GetMailslotInfo函數負責擷取訊息的長度資訊;利用這個函數,程式可以針對長度不定的進入訊息,動態調節其緩衝區大小。GetMailslotInfo也可以用來對進入資料進行“輪詢”。BOOL GetMailslotInfo(HANDLE hMailslot,//CreateMailslot返回的郵件槽控制代碼。LPDWORD lpMaxMessageSize,//設定可將多大的一條訊息寫入郵件槽(位元組單位)。LPDWORD lpNextSize,//下一條訊息的長度,可能返回MAILSLOT_NO_MESSAGE,表明當前沒有等待接收的訊息。LPDWORD lpMessageCount,//函數返回時讀入多少個等待的訊息。LPDWORD lpReadTimeout//等待訊息寫入的時間長度(毫秒)。); SetMailslotInfo:設定郵件槽的逾時值。超過該值讀操作不再等待進入的訊息。BOOL SetMailslotInfo(HANDLE hMailslot,//CreateMailslot返回的郵件槽控制代碼。DWORD lReadTimeout//已毫秒為單位指定讀操作等待一條訊息寫入的最長時間,0,沒有訊息立即返回;MAILSLOT_WAIT_FOREVER永遠等待下去。);  不能取消“阻塞”的I/O請求對於Windows 95和Windows 98,郵件槽伺服器用ReadFile接受資料,假如用MAILSLOT_WAIT_FOREVER標誌建立一個郵件槽,讀請求便會一直等待直到有資料可用為止。如果ReadFile請求尚未完成,伺服器應用突然中止運行,應用程式會被永遠“掛起”或“阻塞”。只有重啟Windows才能取消。為瞭解決這個問題,可讓伺服器在單獨一個線程中,開啟一個控制代碼,令其指向自己的郵件槽。並在需要退出時在主線程中發生資料,以終止處於暫停狀體的讀操作。
  1. //Server2.cpp
  2. //非阻塞伺服器郵件槽,用於接收客戶發送的廣播資訊
  3. #include <windows.h>
  4. #include <stdio.h>
  5. #include <conio.h>
  6. BOOL StopProcessing;
  7. DWORD WINAPI ServeMailslot(LPVOID lpParameter);
  8. void SendMessageToMailslot(void);
  9. int main()
  10. {
  11.     DWORD ThreadId;
  12.     HANDLE MailslotThread;
  13.     StopProcessing = FALSE;
  14.     MailslotThread = CreateThread(NULL,0,ServeMailslot,
  15.         NULL,0,&ThreadId);
  16.     printf("Press a key to stop the server/n");
  17.     _getch();
  18.     //Mark the StopProcessing flag to TRUE so that when ReadFile
  19.     //break, our server thread will end
  20.     StopProcessing = TRUE;
  21.     //Send a message to our mailslot to break the ReadFile call
  22.     //in our server
  23.     SendMessageToMailslot();
  24.     //等待服務線程完成
  25.     if (WAIT_FAILED == WaitForSingleObject(MailslotThread, INFINITE))
  26.     {
  27.         printf("WaitForSingleObject failed with error %d/n",GetLastError());
  28.         return -1;
  29.     }
  30.     
  31.     return 0;
  32. }
  33. //This function is the mailslot server worker function to
  34. //process all incoming mailslot I/O
  35. DWORD WINAPI ServeMailslot(LPVOID lpParameter)
  36. {
  37.     char buffer[2048];
  38.     DWORD NumberOfBytesRead;
  39.     DWORD Ret;
  40.     HANDLE Mailslot;
  41.     Mailslot = CreateMailslot("////.//mailslot//myslot",2048,MAILSLOT_WAIT_FOREVER,NULL);
  42.     if (INVALID_HANDLE_VALUE == Mailslot)
  43.     {
  44.         printf("Failed to create a MailSlot %d/n",GetLastError());
  45.         return -1;
  46.     }
  47.     while (0 != (Ret = ReadFile(Mailslot,buffer,2048,&NumberOfBytesRead,NULL)))
  48.     {
  49.         if (StopProcessing)
  50.             break;
  51.         printf("Received %d bytes/n", NumberOfBytesRead);
  52.     }
  53.     CloseHandle(Mailslot);
  54.     return 0;
  55. }
  56. //The SendMessageToMailslot function is designed to send a
  57. //simple message to our server so we can break the blocking
  58. //ReadFile API call
  59. void SendMessageToMailslot()
  60. {
  61.     HANDLE Mailslot;
  62.     DWORD BytesWritten;
  63.     Mailslot = CreateFile("////.//mailslot//myslot",GENERIC_WRITE, 
  64.         FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
  65.     if (INVALID_HANDLE_VALUE == Mailslot)
  66.     {
  67.         printf("CreateFile failed with error %d/n", GetLastError());
  68.         return;
  69.     }
  70.     if (0 == WriteFile(Mailslot, "STOP", 4, &BytesWritten, NULL))
  71.     {
  72.         printf("WriteFile failed with error %d/n", GetLastError());
  73.         return;
  74.     }
  75.     CloseHandle(Mailslot);
  76. }

【轉】Windows 郵件槽(MailSlot)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.