创建命名管道命名管道常常用于应用程序之间的通迅,由于不需要进行序列化和反序列化操作,效率是非常高的。相比TCP通信方式,效率更高,但比共享内存要低点。
命名管道可以在本地机器或者局域网内机器实现进程间通信,所以是最佳的通信方式。
创建一个NamedPipeServerStream:
NamedPipeServerStream pipeServer =newNamedPipeServerStream(_pipName, PipeDirection.InOut,10);
这里表示命名管道服务器的管道放心为双向通信,类似于TCP双工。接着,使用下面的代码等待连接:
pipeServer.WaitForConnection();
如果有连接,就可以使用流阅读器进行阅读:
StreamReader sr =newStreamReader(pipeServer);
同样,也可以使用流写操作器,将数据写入流,管道的另一端,可以读取这个流:
using(StreamWriter sw =newStreamWriter(pipeServer))
{
sw.AutoFlush=true;
sw.WriteLine("hello world"+str);
}
注意:此处使用了using,意味着写完就会关闭流,但同时也会关闭管道,所以需要注意。假如客户端要读取全部数据,那么需要等到这里关闭流。
自定义应用层通信协议如何读取管道的全部数据,看下面的代码:
StreamReader sr =newStreamReader(pipeServer);stringtext =sr.ReadToEnd();
这种方式可以读取全部数据,但是,在管道的另外一段,如果留写操作器不调用 Close方法,这里没法读取完成,程序会阻塞在这里。 所以,必须定义一个“应用协议”,客户端告诉服务端合适结束读取数据。
我们仿照HTTP协议的方法,使用连续的2个以上的回车换行表示HTTP头信息结束,我们也这样定义,并附加其它标记来表示流数据发送完毕,参考发送端:
publicstringQuery(stringrequest)
{if(!_pipeClient.IsConnected)
{
_pipeClient.Connect(10000);
}
StreamWriter sw=newStreamWriter(_pipeClient);
sw.WriteLine(request);
sw.WriteLine();//连续2个换行外加"#END"表示结束sw.WriteLine();
sw.WriteLine("#END");
sw.Flush();
StreamReader sr=newStreamReader(_pipeClient);stringreturnVal =sr.ReadToEnd();returnreturnVal;
}
而在服务端,采用下面的方式完成流数据的读取:
stringstr =null;stringstrAll =null;
System.Text.StringBuilder sb=newSystem.Text.StringBuilder();
StreamReader sr=newStreamReader(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();elsesb.AppendLine(str);
}
}
strAll= strAll.Substring(0, strAll.Length -"\r\n\r\n\r\n".Length);
测试和下载最后,写个客户端和服务端控制台程序:
namespaceNamePipedSample_Server
{classPRogram
{staticvoidMain(string[] args)
{
NamedPipeListenServer svr=newNamedPipeListenServer("test");
svr.Run();
Console.Read();
}
}
}
namespaceNamePipedSample_Client
{classProgram
{staticvoidMain(string[] args)
{stringsendStr =null;using(NamedPipeClient client =newNamedPipeClient(".","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 =newNamedPipeClient("user-xxxPc","test"))
{//}
但是这样可能还是无法访问,会报下面的错误:
“System.IO.IOException”类型的未经处理的异常在 System.Core.dll 中发生
其他信息: 登录失败: 未知的用户名或错误密码。
此时需要在客户机器上,地址栏里面输入下面的地址: \\user-xxxPc
此时会提示输入用户名,密码,最后勾选 “记住账号”,下次即可使用了。
经过测试,这种方法是先命名管道客户端-服务器通信成功。 本文程序是在网友原来文章的基础上改进的,在此表示感谢,原文地址: http://blog.csdn.net/educast/article/details/7219774
本文程序Demo下载