您的位置:首页 > 其它

.net 命名管道(NamedPipe) 的使用

2011-07-12 10:41 393 查看
命名管道常常用于应用程序之间的通迅,由于不需要进行序列化和反序列化操作,效率还是非常高的。我们今天做个演示看看。

类似于TCP/IP的模式的c/s结构。我们先建立一个服务器端:

using (NamedPipeServerStream pipeServer =
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 ”

下面写一个客户端。

using (NamedPipeClientStream pipeClient =
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;
}

/// <summary>
/// 创建一个NamedPipeServerStream
/// </summary>
/// <returns></returns>
protected NamedPipeServerStream CreateNamedPipeServerStream()
{
NamedPipeServerStream npss = new NamedPipeServerStream(_pipName, PipeDirection.InOut, 10);
_serverPool.Add(npss);
Console.WriteLine("启动了一个NamedPipeServerStream " + npss.GetHashCode());
return npss;
}

/// <summary>
/// 销毁
/// </summary>
/// <param name="npss"></param>
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);
}
}

}

/// <summary>
/// 处理消息
/// </summary>
/// <param name="str"></param>
/// <param name="pipeServer"></param>
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);
}
}

/// <summary>
/// 停止
/// </summary>
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;

/// <summary>
///
/// </summary>
/// <param name="serverName">服务器地址</param>
/// <param name="pipName">管道名称</param>
public NamedPipeClient(string serverName, string pipName)
{
_serverName = serverName;
_pipName = pipName;

_pipeClient = new NamedPipeClientStream(serverName, pipName, PipeDirection.InOut);

}

/// <summary>
/// 查询
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
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对象,实际会将输入参数的内容发送往服务端,将服务端的处理结果做为该方法的返回值。

服务端使用演示:

NamedPipeListenServer svr = new NamedPipeListenServer("test");
svr.Run();
客户端使用演示:

using (NamedPipeClient client = new NamedPipeClient(".","test"))
{
MessageBox.Show( client.Query("fff"));
MessageBox.Show(client.Query("54353"));
}

呵呵,使用起来更简单和方便了。而且完全不用考虑内部的命名管道连接。

本文完。

完整的代码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: