• 推荐
  • 评论
  • 收藏

管道的基本用法

2022-12-22    3721次浏览

有关管道的基本用法请看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系列:局域网内多线程使用命名管道在进程之间通信实例


请尊重作者的劳动,转载请保留链接 玉开的技术博客

原文地址:https://www.cnblogs.com/Leo_wl/p/2132654.html