有關管道的基本用法請看System.IO之使用管道在進程間通信 (System.IO.Pipes使用)。
本文介紹命名管道使用實例,文中例子是幾個客戶端都通過一台服務器獲得新生成的int類型id。
服務器端功能:當客戶端請求一個新的id時,將現有id自增1,然後返回給客戶端。
服務器端實現:在程序啟動時,啟動n個線程,在每個線程中都聲明一個NamedPipeServerStream的實例,並循環的WaitForConnection(),將新的id寫入到命名管道中,然後斷開連接。在程序退出時釋放NamedPipeServerStream實例
如下代碼實現:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
| 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。
如下代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
| 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異常。
本例不可以在實際項目中使用。