1. 命名管道簡介
"命名管道"或"命名管線"(Named Pipes)是一種簡單的進程間通信(I P C)機制,Microsoft Windows NT,Windows 2000,Windows 95以及Windows 98均提供了對它的支持(但不包括Windows CE).命名管道可在同一台計算機的不同進程之間,或在跨越一個網絡的不同計算機的不同進程之間,支持可靠的,單向或雙向的數據通信.用命名管道來設計應用程序實際非常簡單,並不需要事先深入掌握基層網絡傳送協議(如T C P / I P或I P X)的知識.這是由於命名管道利用了微軟網絡提供者(M S N P)重定向器,通過一個網絡,在各進程間建立通信.這樣一來,應用程序便不必關心網絡協議的細節.之所以要用命名管道作為自己的網絡通信方案,一項重要的原因是它們充分利用了Windows NT及Windows 2000內建的安全特性.
2.命名管道作用
這里有一個可采納命令管道的例子.假定我們要開發一個數據管理系統,只允許一個指定的用戶組進行操作.想像在自己的辦公室中,有一部計算機,其中保存着公司的秘密.我們要求只有公司的管理人員,才能訪問及處理這些秘密.假定在自己的工作站機器上,公司內的每名員工都可看到網絡上的這台計算機.然而,我們並不希望普通員工取得對機密材料的訪問權.在這種情況下,命名管道可發揮出很好的作用,因為我們可開發一個服務器應用程序,令其以來自客戶機的請求為准,對公司的秘密進行安全操作.服務器可將客戶訪問限制在管理人員身上,用Windows NT或新版Windows 2000自帶的安全機制,便可非常輕松地做到這一點.在此要記住的一個重點是,將命名管道作為一種網絡編程方案使用時,它實際上建立一個簡單的客戶機/服務器數據通信體系,可在其中可靠地傳輸數據.
3. 命名管道優點
使用比較方便,並且不需要聲明端口號之類的,在程序中不需要關心權限之類的。
4. 命名管道限制(我個人認為)
管道只能一對一鏈接通信。
5. 命名管道實現
5.1 命名管道通訊輔助類
/// <summary> /// pipe命名管道通訊輔助類 /// </summary> public class StreamString { private Stream ioStream; private UnicodeEncoding streamEncoding; public StreamString(Stream ioStream) { this.ioStream = ioStream; streamEncoding = new UnicodeEncoding(); } public string ReadString() { try { int len; len = ioStream.ReadByte() * 256; len += ioStream.ReadByte(); byte[] inBuffer = new byte[len]; ioStream.Read(inBuffer, 0, len); return streamEncoding.GetString(inBuffer); } catch (Exception) { return null; } } public int WriteString(string outString) { byte[] outBuffer = streamEncoding.GetBytes(outString); int len = outBuffer.Length; if (len > UInt16.MaxValue) { len = (int)UInt16.MaxValue; } ioStream.WriteByte((byte)(len / 256)); ioStream.WriteByte((byte)(len & 255)); ioStream.Write(outBuffer, 0, len); ioStream.Flush(); return outBuffer.Length + 2; } } /// <summary> /// 自定義包裝類 /// </summary> public class StringToStream { private string Contents; private StreamString streamString; public StringToStream(StreamString ss, string contents) { Contents = contents; streamString = ss; } public void Start() { //string contents = File.ReadAllText(fn); streamString.WriteString(Contents); } }
5.2 命名管道服務器端幫助類
public class PipeHelp { private static int numThreads = 1; /// <summary> /// 啟動管道服通訊務器 /// </summary> public static void PipeSeverSart() { try { int i; Thread[] servers = new Thread[numThreads]; Console.WriteLine("Waiting for client connect...\n"); for (i = 0; i < numThreads; i++) { servers[i] = new Thread(ServerThread); servers[i].Start(); } } catch (Exception) { throw new Exception("管道服務啟動失敗."); //PipeSeverSart(); } } /// <summary> /// 退出管道。(程序退出時別忘了調用) /// </summary> public static void PipeSeverClose() { if (pipeServer != null) { try { pipeServer.Disconnect(); pipeServer.Close(); } catch (Exception exception) { Console.WriteLine(exception.Message); } } } private static NamedPipeServerStream pipeServer; /// <summary> /// 處理函數 /// </summary> /// <param name="data"></param> private static void ServerThread(object data) { try { Random reRandom = new Random(); pipeServer = new NamedPipeServerStream("VisualPlatformPipe", PipeDirection.InOut, numThreads); //int threadId = Thread.CurrentThread.ManagedThreadId; // Wait for a client to connect pipeServer.WaitForConnection(); StreamString ss = new StreamString(pipeServer); //Console.WriteLine("Client connected on thread[{0}].", threadId); while (true) { try { // Read the request from the client. Once the client has // written to the pipe its security token will be available. //ss.WriteString("I am the one true server!"); string temp = ss.ReadString(); if (temp != null) { if (temp.ToLower() == "close")//客戶端通知服務器客戶端退出 { //為了客戶端退出之后,可以再次連接到服務器端,重新設置一下服務i其管道 Close(); pipeServer = new NamedPipeServerStream("VisualPlatformPipe", PipeDirection.InOut, numThreads); pipeServer.WaitForConnection(); ss = new StreamString(pipeServer); } else { StringToStream fileReader = new StringToStream(ss, SystemHelp.BusinessSystemID); pipeServer.RunAsClient(fileReader.Start); } } else////客戶端未通知服務器客戶端退出,客戶端直接異常退出 { Close(); pipeServer = new NamedPipeServerStream("VisualPlatformPipe", PipeDirection.InOut, numThreads); pipeServer.WaitForConnection(); ss = new StreamString(pipeServer); } } // Catch the IOException that is raised if the pipe is broken // or disconnected. catch (IOException e) { Console.WriteLine("ERROR: {0}", e.Message); } } } catch (Exception) { throw new Exception("管道服務啟動失敗."); } } /// <summary> /// 退出管道 /// </summary> public static void Close() { if (pipeServer != null) { pipeServer.Disconnect(); pipeServer.Close(); } } }
5.3客戶端幫助類
public class PipeClientHelp { private static StreamString m_StreamString = null; private static NamedPipeClientStream pipeClient = null; /// <summary> /// 啟動客戶端,連接服務器,只允許連接一次 /// </summary> /// <returns></returns> public static bool StartConnection() { try { if (pipeClient == null) { pipeClient = new NamedPipeClientStream(".", "VisualPlatformPipe", PipeDirection.InOut, PipeOptions.None, TokenImpersonationLevel.Impersonation); pipeClient.Connect(100); m_StreamString = new StreamString(pipeClient); } } catch (Exception exception) { pipeClient = null; throw new Exception("未啟動服務器端" + exception.Message); } return true; } /// <summary> /// 通知服務器客戶端即將退出 /// </summary> public static void ClosePipe() { if (pipeClient != null) { m_StreamString.WriteString("close"); m_StreamString = null; pipeClient.Close(); pipeClient = null; } } /// <summary> /// 從服務器獲取數據 /// </summary> /// <returns></returns> public static string GetSystemID() { if (m_StreamString != null) { m_StreamString.WriteString("GetBusinessSystemId"); return m_StreamString.ReadString(); } return null; } }