有关管道的基本用法请看System.IO之使用管道在进程间通信 (System.IO.Pipes使用)。
本文介绍命名管道使用实例,文中例子是几个客户端都通过一台服务器获得新生成的int类型id。
服务器端功能:当客户端请求一个新的id时,将现有id自增1,然后返回给客户端。
服务器端实现:在程序启动时,启动n个线程,在每个线程中都声明一个NamedPipeServerStream的实例,并循环的 WaitForConnection(),将新的id写入到命名管道中,然后断开连接。在程序退出时释放NamedPipeServerStream实例
如下代码实现:
001 |
using System; |
002 |
using System.Collections.Generic; |
003 |
using System.Linq; |
004 |
using System.Text; |
005 |
006 |
007 |
using System.IO; |
008 |
using System.IO.Pipes; |
009 |
using System.Threading; |
010 |
011 |
namespace IDServer |
012 |
{ |
013 |
class Program |
014 |
{ |
015 |
/// <summary> |
016 |
/// 命名管道名字 |
017 |
/// </summary> |
018 |
private const string PIPE_NAME = "testNetworkPipe" ; |
019 |
020 |
//定义线程数,也是NamedPipeServerStream的允许最多的实例数 |
021 |
private const int MAX_THREADS_COUNT = 3; |
022 |
private static volatile int _runingThreadCount = 0; |
023 |
024 |
private static volatile int _newId = 0; |
025 |
026 |
//实例数组 |
027 |
private static NamedPipeServerStream[] _serverStreams; |
028 |
029 |
static void Main( string [] args) |
030 |
{ |
031 |
_serverStreams = new NamedPipeServerStream[MAX_THREADS_COUNT]; |
032 |
033 |
//在进程退出时释放所有NamedPipeServerStream实例 |
034 |
AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit); |
035 |
|
036 |
//启动线程 |
037 |
StartServers(); |
038 |
039 |
Console.Read(); |
040 |
} |
041 |
042 |
/// <summary> |
043 |
/// 在进程退出时释放命名管道 |
044 |
/// </summary> |
045 |
/// <param name="sender"></param> |
046 |
/// <param name="e"></param> |
047 |
static void CurrentDomain_ProcessExit( object sender, EventArgs e) |
048 |
{ |
049 |
if (_serverStreams != null ) |
050 |
{ |
051 |
foreach (NamedPipeServerStream item in _serverStreams) |
052 |
{ |
053 |
item.Dispose(); |
054 |
} |
055 |
} |
056 |
} |
057 |
058 |
/// <summary> |
059 |
/// 启动服务器端线程 |
060 |
/// </summary> |
061 |
private static void StartServers() |
062 |
{ |
063 |
for ( int i = 0; i < MAX_THREADS_COUNT; i++) |
064 |
{ |
065 |
Thread thread = new Thread( new ThreadStart(StartNewIDServer)); |
066 |
thread.Start(); |
067 |
} |
068 |
} |
069 |
070 |
071 |
/// <summary> |
072 |
/// 启动一个NamedPipeServerStream实例 |
073 |
/// </summary> |
074 |
private static void StartNewIDServer() |
075 |
{ |
076 |
NamedPipeServerStream stream = null ; |
077 |
Console.WriteLine( "start server in thread " + Thread.CurrentThread.ManagedThreadId); |
078 |
079 |
stream = _serverStreams[_runingThreadCount] = new NamedPipeServerStream(PIPE_NAME, |
080 |
PipeDirection.InOut, |
081 |
MAX_THREADS_COUNT, |
082 |
PipeTransmissionMode.Message, |
083 |
PipeOptions.None); |
084 |
int threadNo = _runingThreadCount; |
085 |
_runingThreadCount += 1; |
086 |
087 |
while ( true ) |
088 |
{ |
089 |
stream.WaitForConnection(); |
090 |
int newId = ++_newId; |
091 |
092 |
byte [] bytes = BitConverter.GetBytes(newId); |
093 |
stream.Write(bytes, 0, bytes.Length); |
094 |
stream.Flush(); |
095 |
Console.Write( "threadNo:" + Thread.CurrentThread.ManagedThreadId + "\r" ); |
096 |
stream.Disconnect(); |
097 |
} |
098 |
} |
099 |
100 |
} |
101 |
} |
客户端的功能是不断的发出获得新id的请求,并打印新id,在客户端可以配置服务端的服务器IP。
如下代码:
01 |
using System; |
02 |
using System.Collections.Generic; |
03 |
using System.Linq; |
04 |
using System.Text; |
05 |
using System.Threading; |
06 |
07 |
namespace IDClient |
08 |
{ |
09 |
class Program |
10 |
{ |
11 |
private const string PIPE_NAME = "testNetworkPipe" ; |
12 |
13 |
static void Main( string [] args) |
14 |
{ |
15 |
Console.WriteLine( "请输入任何字符回车开始执行程序.." ); |
16 |
Console.Read(); |
17 |
do |
18 |
{ |
19 |
//内网服务器ip,必须是局域网 |
20 |
string serverName = "127.0.0.1" ; |
21 |
//声明NamedPipeClientStream实例 |
22 |
using (var clientStream = new System.IO.Pipes.NamedPipeClientStream(serverName, PIPE_NAME)) |
23 |
{ |
24 |
//连接服务器 |
25 |
clientStream.Connect(1000); |
26 |
//设置为消息读取模式 |
27 |
clientStream.ReadMode = System.IO.Pipes.PipeTransmissionMode.Message; |
28 |
29 |
do |
30 |
{ |
31 |
byte [] bytes = new byte [4]; |
32 |
clientStream.Read(bytes, 0, 4); |
33 |
int val = BitConverter.ToInt32(bytes, 0); |
34 |
Console.Write( "NewID == " + val + "\r" ); |
35 |
} while (!clientStream.IsMessageComplete); |
36 |
} |
37 |
38 |
Thread.Sleep(1); |
39 |
} while ( true ); |
40 |
} |
41 |
} |
42 |
} |
在sql server中就使用了命名管道在局域网内挂进程通讯。
在声明NamedPipeServerStream实例是可以指定其实例个数,如果实例数超过这个数,就会抛出“所有管道范例都在使用中”的IO异常。
本例不可以在实际项目中使用。
相关随笔:
.Net那点事儿系列:System.IO之windows文件操作
.Net那点事儿系列:System.IO之Stream
System.IO之内存映射文件共享内存
System.IO之使用管道在进程间通信 (System.IO.Pipes使用)
System.IO系列:局域网内多线程使用命名管道在进程之间通信实例
请尊重作者的劳动,转载请保留链接 玉开的技术博客
玉开的技术随笔推荐