命名管道常常用于應(yīng)用程序之間的通迅,由于不需要進(jìn)行序列化和反序列化操作,效率是非常高的。相比TCP通信方式,效率更高,但比共享內(nèi)存要低點(diǎn)。
命名管道可以在本地機(jī)器或者局域網(wǎng)內(nèi)機(jī)器實(shí)現(xiàn)進(jìn)程間通信,所以是最佳的通信方式。
創(chuàng)建一個(gè)NamedPipeServerStream:
NamedPipeServerStream pipeServer = new NamedPipeServerStream(_pipName, PipeDirection.InOut, 10);
這里表示命名管道服務(wù)器的管道放心為雙向通信,類似于TCP雙工。接著,使用下面的代碼等待連接:
pipeServer.WaitForConnection();
如果有連接,就可以使用流閱讀器進(jìn)行閱讀:
StreamReader sr = new StreamReader(pipeServer);
同樣,也可以使用流寫操作器,將數(shù)據(jù)寫入流,管道的另一端,可以讀取這個(gè)流:
using (StreamWriter sw = new StreamWriter(pipeServer)) { sw.AutoFlush = true; sw.WriteLine("hello world " + str); }
注意:此處使用了using,意味著寫完就會(huì)關(guān)閉流,但同時(shí)也會(huì)關(guān)閉管道,所以需要注意。假如客戶端要讀取全部數(shù)據(jù),那么需要等到這里關(guān)閉流。
如何讀取管道的全部數(shù)據(jù),看下面的代碼:
StreamReader sr = new StreamReader(pipeServer); string text =sr.ReadToEnd();
這種方式可以讀取全部數(shù)據(jù),但是,在管道的另外一段,如果留寫操作器不調(diào)用 Close方法,這里沒法讀取完成,程序會(huì)阻塞在這里。 所以,必須定義一個(gè)“應(yīng)用協(xié)議”,客戶端告訴服務(wù)端合適結(jié)束讀取數(shù)據(jù)。
我們仿照HTTP協(xié)議的方法,使用連續(xù)的2個(gè)以上的回車換行表示HTTP頭信息結(jié)束,我們也這樣定義,并附加其它標(biāo)記來表示流數(shù)據(jù)發(fā)送完畢,參考發(fā)送端:
public string Query(string request) { if (!_pipeClient.IsConnected) { _pipeClient.Connect(10000); } StreamWriter sw = new StreamWriter(_pipeClient); sw.WriteLine(request); sw.WriteLine();//連續(xù)2個(gè)換行外加"#END"表示結(jié)束 sw.WriteLine(); sw.WriteLine("#END"); sw.Flush(); StreamReader sr = new StreamReader(_pipeClient); string returnVal = sr.ReadToEnd(); return returnVal; }
而在服務(wù)端,采用下面的方式完成流數(shù)據(jù)的讀取:
string str = null; string strAll = null; System.Text.StringBuilder sb = new System.Text.StringBuilder(); StreamReader sr = new StreamReader(pipeServer); while (pipeServer.CanRead && (null != (str = sr.ReadLine()))) { //當(dāng)遇到連續(xù)2個(gè)換行外加#END,表示輸入結(jié)束 if (str == "#END" ) { strAll = sb.ToString(); if (strAll.EndsWith("/r/n/r/n")) break; } else { if (str == "") sb.AppendLine(); else sb.AppendLine(str); } } strAll = strAll.Substring(0, strAll.Length - "/r/n/r/n/r/n".Length);
最后,寫個(gè)客戶端和服務(wù)端控制臺(tái)程序:
namespace NamePipedSample_Server{ class PRogram { static void Main(string[] args) { NamedPipeListenServer svr = new NamedPipeListenServer("test"); svr.Run(); Console.Read(); } }}
namespace NamePipedSample_Client{ class Program { static void Main(string[] args) { string sendStr = null; using (NamedPipeClient client = new NamedPipeClient(".", "test")) { sendStr = "fff/r/ndddd/r/n"; Console.WriteLine("send:{0}",sendStr); Console.WriteLine("Reply:{0}",client.Query(sendStr)); sendStr = "54353"; Console.WriteLine("send:{0}", sendStr); Console.WriteLine("Reply:{0}", client.Query(sendStr)); sendStr = "aaaaaaa"; Console.WriteLine("send:{0}", sendStr); Console.WriteLine("Reply:{0}", client.Query(sendStr)); } Console.WriteLine("send all ok."); Console.Read(); } }}
上面的程序在本地機(jī)器使用沒問題的,但是跨機(jī)器可能會(huì)遇到問題,在使用的時(shí)候,需要將主機(jī)名字 "." 替換成
實(shí)際的局域網(wǎng)主機(jī)名字,例如:
using (NamedPipeClient client = new NamedPipeClient("user-xxxPc", "test")){ //}
但是這樣可能還是無法訪問,會(huì)報(bào)下面的錯(cuò)誤:
“System.IO.IOException”類型的未經(jīng)處理的異常在 System.Core.dll 中發(fā)生 其他信息: 登錄失敗: 未知的用戶名或錯(cuò)誤密碼。
此時(shí)需要在客戶機(jī)器上,地址欄里面輸入下面的地址: //user-xxxPc
此時(shí)會(huì)提示輸入用戶名,密碼,最后勾選 “記住賬號(hào)”,下次即可使用了。
經(jīng)過測(cè)試,這種方法是先命名管道客戶端-服務(wù)器通信成功。 本文程序是在網(wǎng)友原來文章的基礎(chǔ)上改進(jìn)的,在此表示感謝,原文地址: http://blog.csdn.net/educast/article/details/7219774
本文程序Demo下載
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注