命名管道常常用于应用程序之间的通迅,由于不需要进行序列化和反序列化操作,效率还是非常高的。我们今天做个演示看看。
类似于TCP/IP的模式的c/s结构。我们先建立一个服务器端:
new NamedPipeServerStream( " testpipe " , PipeDirection.Out))//创建连接
{
pipeServer.WaitForConnection();//等待连接,程序会阻塞在此处,直到有一个连接到达
try
{
// Read user input and send that to the client process.
using (StreamWriter sw = new StreamWriter(pipeServer))
{
sw.AutoFlush = true ;
sw.WriteLine( " hello world " );
}
}
// Catch the IOException that is raised if the pipe is broken
// or disconnected.
catch (IOException e)
{
Console.WriteLine( " ERROR: {0} " , e.Message);
}
}
上面的代码很简单,构建NamedPipeServerStream对象,然后调用该对象的WaitForConnection方法等待客户端的连接,一旦连接建立,向客户端写入一个字符串“hello world ”
下面写一个客户端。
new NamedPipeClientStream( " . " , " testpipe " , PipeDirection.In))
{
pipeClient.Connect();
using (StreamReader sr = new StreamReader(pipeClient))
{
string temp;
while ((temp = sr.ReadLine()) != null )
{
MessageBox.Show( string .Format( " Received from server: {0} " , temp));
}
}
}
客户端构建了一个NamedPipeClientStream 对象,调用Connect方法建立连接,连接通畅后,立即从通道里读取数据,这里会读取到"hello world "字符。
本文结束。太简单了吧。微软都把这些类库封装的很方便了。
---------------------
以下是扩充内容。
既然 命名管道 给我们提供一种通讯方式,那么我们尝试使用这个通讯做个 C/S 结构的消息监听演示。我们利用 命名管道 封装两个类,一个服务类,一个客户机类。使得我们在使用的时候无需考虑通讯的底层实现。
那么我们先看下服务端的类:
* @名称 :
* @描述 :
* @创建人 : 张云飞
* @创建日期: 2011/7/12 9:57:55
* @修改记录:
* ---------------------------------------------------------- */
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO.Pipes;
using System.IO;
using System.Threading;
namespace SimpleCode.NamedPipeLib
{
public class NamedPipeListenServer
{
List < NamedPipeServerStream > _serverPool = new List < NamedPipeServerStream > ();
string _pipName = " test " ;
public NamedPipeListenServer( string pipName)
{
_pipName = pipName;
}
///
/// 创建一个NamedPipeServerStream
///
///
protected NamedPipeServerStream CreateNamedPipeServerStream()
{
NamedPipeServerStream npss = new NamedPipeServerStream(_pipName, PipeDirection.InOut, 10 );
_serverPool.Add(npss);
Console.WriteLine( " 启动了一个NamedPipeServerStream " + npss.GetHashCode());
return npss;
}
///
/// 销毁
///
///
protected void DistroyObject(NamedPipeServerStream npss)
{
npss.Close();
if (_serverPool.Contains(npss))
{
_serverPool.Remove(npss);
}
Console.WriteLine( " 销毁一个NamedPipeServerStream " + npss.GetHashCode());
}
public void Run()
{
using (NamedPipeServerStream pipeServer = CreateNamedPipeServerStream())
{
pipeServer.WaitForConnection();
Console.WriteLine( " 建立一个连接 " + pipeServer.GetHashCode());
Action act = new Action(Run);
act.BeginInvoke( null , null );
try
{
bool isRun = true ;
while (isRun)
{
string str = null ;
StreamReader sr = new StreamReader(pipeServer);
while (pipeServer.CanRead && ( null != (str = sr.ReadLine())))
{
ProcessMessage(str, pipeServer);
if ( ! pipeServer.IsConnected)
{
isRun = false ;
break ;
}
}
Thread.Sleep( 50 );
}
}
// Catch the IOException that is raised if the pipe is broken
// or disconnected.
catch (IOException e)
{
Console.WriteLine( " ERROR: {0} " , e.Message);
}
finally
{
DistroyObject(pipeServer);
}
}
}
///
/// 处理消息
///
///
///
protected virtual void ProcessMessage( string str, NamedPipeServerStream pipeServer)
{
// Read user input and send that to the client process.
using (StreamWriter sw = new StreamWriter(pipeServer))
{
sw.AutoFlush = true ;
sw.WriteLine( " hello world " + str);
}
}
///
/// 停止
///
public void Stop()
{
for ( int i = 0 ; i < _serverPool.Count; i ++ )
{
var item = _serverPool[i];
DistroyObject(item);
}
}
}
}
我们使用 List<NamedPipeServerStream> _serverPool 做为一个集合容器,记录和保存所有的建立的连接。在Run方法里创建新的 命名管道连接 的实例。注意我们这里使用了一个异步委托。
Action act = new Action(Run);
act.BeginInvoke(null, null);
在一个Run方法执行时,异步执行了另一个Run方法,在这个Run方法的实现了阻塞监听,也就是一个新的连接建立后,立即建立一个新的监听连接,使得在处理一个连接的数据时,也可以等待新的客户端连接进入。
Stop方法会遍历所有的连接,保证销毁所有的连接。 ProcessMessage方法是处理客户机发来的消息,我们这里使用了ReadLine方法,也就是我们认为一行作为一个消息的单元。注意这个方法是virtual的,我们可以实现它的重载,以增加新的消息处理方式。
下面是客户端的封装类:
* @名称 :
* @描述 :
* @创建人 : 张云飞
* @创建日期: 2011/7/12 11:31:30
* @修改记录:
* ---------------------------------------------------------- */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Pipes;
using System.IO;
namespace SimpleCode.NamedPipeLib
{
public class NamedPipeClient : IDisposable
{
string _serverName;
string _pipName;
NamedPipeClientStream _pipeClient;
///
///
///
/// 服务器地址
/// 管道名称
public NamedPipeClient( string serverName, string pipName)
{
_serverName = serverName;
_pipName = pipName;
_pipeClient = new NamedPipeClientStream(serverName, pipName, PipeDirection.InOut);
}
///
/// 查询
///
///
///
public string Query( string request)
{
if ( ! _pipeClient.IsConnected)
{
_pipeClient.Connect( 10000 );
}
StreamWriter sw = new StreamWriter(_pipeClient);
sw.WriteLine(request);
sw.Flush();
StreamReader sr = new StreamReader(_pipeClient);
string temp;
string returnVal = "" ;
while ((temp = sr.ReadLine()) != null )
{
returnVal = temp;
// nothing
}
return returnVal;
}
#region IDisposable 成员
bool _disposed = false ;
public void Dispose()
{
if ( ! _disposed && _pipeClient != null )
{
_pipeClient.Dispose();
_disposed = true ;
}
}
#endregion
}
}
这个类需要注意的是,在构造里构造类命名管道的对象。有意思的地方是Query方法,该方法会接受一个string参数,并且返回一个string对象,实际会将输入参数的内容发送往服务端,将服务端的处理结果做为该方法的返回值。
服务端使用演示:
svr.Run();
客户端使用演示:
{
MessageBox.Show( client.Query( " fff " ));
MessageBox.Show(client.Query( " 54353 " ));
}
呵呵,使用起来更简单和方便了。而且完全不用考虑内部的命名管道连接。
本文完。
完整的代码下载