您的位置:首页 > 其它

System.IO系列:局域网内多线程使用命名管道在进程之间通信实例

2011-08-08 16:29 931 查看
有关管道的基本用法请看System.IO之使用管道在进程间通信 (System.IO.Pipes使用)

本文介绍命名管道使用实例,文中例子是几个客户端都通过一台服务器获得新生成的int类型id。

服务器端功能:当客户端请求一个新的id时,将现有id自增1,然后返回给客户端。

服务器端实现:在程序启动时,启动n个线程,在每个线程中都声明一个NamedPipeServerStream的实例,并循环的WaitForConnection(),将新的id写入到命名管道中,然后断开连接。在程序退出时释放NamedPipeServerStream实例

如下代码实现:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.IO;
using System.IO.Pipes;
using System.Threading;

namespace IDServer
{
class Program
{
/// <summary>
/// 命名管道名字
/// </summary>
private const string PIPE_NAME = "testNetworkPipe";

//定义线程数,也是NamedPipeServerStream的允许最多的实例数
private const int MAX_THREADS_COUNT = 3;
private static volatile int _runingThreadCount = 0;

private static volatile int _newId = 0;

//实例数组
private static NamedPipeServerStream[] _serverStreams;

static void Main(string[] args)
{
_serverStreams = new NamedPipeServerStream[MAX_THREADS_COUNT];

//在进程退出时释放所有NamedPipeServerStream实例
AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);

//启动线程
StartServers();

Console.Read();
}

/// <summary>
/// 在进程退出时释放命名管道
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
static void CurrentDomain_ProcessExit(object sender, EventArgs e)
{
if (_serverStreams != null)
{
foreach (NamedPipeServerStream item in _serverStreams)
{
item.Dispose();
}
}
}

/// <summary>
/// 启动服务器端线程
/// </summary>
private static void StartServers()
{
for (int i = 0; i < MAX_THREADS_COUNT; i++)
{
Thread thread = new Thread(new ThreadStart(StartNewIDServer));
thread.Start();
}
}

/// <summary>
/// 启动一个NamedPipeServerStream实例
/// </summary>
private static void StartNewIDServer()
{
NamedPipeServerStream stream = null;
Console.WriteLine("start server in thread " + Thread.CurrentThread.ManagedThreadId);

stream = _serverStreams[_runingThreadCount] = new NamedPipeServerStream(PIPE_NAME,
PipeDirection.InOut,
MAX_THREADS_COUNT,
PipeTransmissionMode.Message,
PipeOptions.None);
int threadNo = _runingThreadCount;
_runingThreadCount += 1;

while (true)
{
stream.WaitForConnection();
int newId = ++_newId;

byte[] bytes = BitConverter.GetBytes(newId);
stream.Write(bytes, 0, bytes.Length);
stream.Flush();
Console.Write("threadNo:" + Thread.CurrentThread.ManagedThreadId + "\r");
stream.Disconnect();
}
}

}
}
客户端的功能是不断的发出获得新id的请求,并打印新id,在客户端可以配置服务端的服务器IP。

如下代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace IDClient
{
class Program
{
private const string PIPE_NAME = "testNetworkPipe";

static void Main(string[] args)
{
Console.WriteLine("请输入任何字符回车开始执行程序..");
Console.Read();
do
{
//内网服务器ip,必须是局域网
string serverName = "127.0.0.1";
//声明NamedPipeClientStream实例
using (var clientStream = new System.IO.Pipes.NamedPipeClientStream(serverName, PIPE_NAME))
{
//连接服务器
clientStream.Connect(1000);
//设置为消息读取模式
clientStream.ReadMode = System.IO.Pipes.PipeTransmissionMode.Message;

do
{
byte[] bytes = new byte[4];
clientStream.Read(bytes, 0, 4);
int val = BitConverter.ToInt32(bytes, 0);
Console.Write("NewID == " + val + "\r");
} while (!clientStream.IsMessageComplete);
}

Thread.Sleep(1);
} while (true);
}
}
}
在sql server中就使用了命名管道在局域网内挂进程通讯。

在声明NamedPipeServerStream实例是可以指定其实例个数,如果实例数超过这个数,就会抛出“所有管道范例都在使用中”的IO异常。

本例不可以在实际项目中使用。

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