命名管道经常用于应用程序之间的通迅,因为不须要进行序列化和反序列化操做,效率是很是高的。相比TCP通讯方式,效率更高,但比共享内存要低点。
命名管道能够在本地机器或者局域网内机器实现进程间通讯,因此是最佳的通讯方式。服务器
建立一个NamedPipeServerStream:测试
NamedPipeServerStream pipeServer = new NamedPipeServerStream(_pipName, PipeDirection.InOut, 10);
这里表示命名管道服务器的管道放心为双向通讯,相似于TCP双工。接着,使用下面的代码等待链接:ui
pipeServer.WaitForConnection();
若是有链接,就可使用流阅读器进行阅读:spa
StreamReader sr = new StreamReader(pipeServer);
一样,也可使用流写操做器,将数据写入流,管道的另外一端,能够读取这个流:.net
using (StreamWriter sw = new StreamWriter(pipeServer)) { sw.AutoFlush = true; sw.WriteLine("hello world " + str); }
注意:此处使用了using,意味着写完就会关闭流,但同时也会关闭管道,因此须要注意。假如客户端要读取所有数据,那么须要等到这里关闭流。code
如何读取管道的所有数据,看下面的代码:blog
StreamReader sr = new StreamReader(pipeServer); string text =sr.ReadToEnd();
这种方式能够读取所有数据,可是,在管道的另一段,若是留写操做器不调用 Close方法,这里无法读取完成,程序会阻塞在这里。 因此,必须定义一个“应用协议”,客户端告诉服务端合适结束读取数据。进程
咱们仿照HTTP协议的方法,使用连续的2个以上的回车换行表示HTTP头信息结束,咱们也这样定义,并附加其它标记来表示流数据发送完毕,参考发送端:ip
public string Query(string request) { if (!_pipeClient.IsConnected) { _pipeClient.Connect(10000); } StreamWriter sw = new StreamWriter(_pipeClient); sw.WriteLine(request); sw.WriteLine();//连续2个换行外加"#END"表示结束 sw.WriteLine(); sw.WriteLine("#END"); sw.Flush(); StreamReader sr = new StreamReader(_pipeClient); string returnVal = sr.ReadToEnd(); return returnVal; }
而在服务端,采用下面的方式完成流数据的读取:内存
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()))) { //当遇到连续2个换行外加#END,表示输入结束 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);
最后,写个客户端和服务端控制台程序:
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(); } } }
上面的程序在本地机器使用没问题的,可是跨机器可能会遇到问题,在使用的时候,须要将主机名字 "." 替换成
实际的局域网主机名字,例如:
using (NamedPipeClient client = new NamedPipeClient("user-xxxPc", "test")) { // }
可是这样可能仍是没法访问,会报下面的错误:
“System.IO.IOException”类型的未经处理的异常在 System.Core.dll 中发生 其余信息: 登陆失败: 未知的用户名或错误密码。
此时须要在客户机器上,地址栏里面输入下面的地址: \\user-xxxPc
此时会提示输入用户名,密码,最后勾选 “记住帐号”,下次便可使用了。
通过测试,这种方法是先命名管道客户端-服务器通讯成功。 本文程序是在网友原来文章的基础上改进的,在此表示感谢,原文地址: http://blog.csdn.net/educast/article/details/7219774
本文程序Demo下载