多个管道服务器实例的异步 NamedPipes
Posted
技术标签:
【中文标题】多个管道服务器实例的异步 NamedPipes【英文标题】:Async NamedPipes in case of multiple pipe server instances 【发布时间】:2014-07-11 15:32:57 【问题描述】:我正在使用来自 this article 的代码,唯一的区别是 maxNumberOfServerInstances 设置为 -1(具有相同管道名称的服务器实例的数量仅受系统资源)在 NamedPipeServerStream 构造函数
异步监听方法【监听服务器类】:
class PipeServer
string _pipeName;
public void Listen(string PipeName)
try
// Set to class level var so we can re-use in the async callback method
_pipeName = PipeName;
// Create the new async pipe
NamedPipeServerStream pipeServer = new NamedPipeServerStream(PipeName,
PipeDirection.In, -1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
// Wait for a connection
pipeServer.BeginWaitForConnection
(new AsyncCallback(WaitForConnectionCallBack), pipeServer);
catch (Exception oEX)
...
private void WaitForConnectionCallBack(IAsyncResult iar)
try
// Get the pipe
NamedPipeServerStream pipeServer = (NamedPipeServerStream)iar.AsyncState;
// End waiting for the connection
pipeServer.EndWaitForConnection(iar);
// Read the incoming message
byte[] buffer = new byte[255];
pipeServer.Read(buffer, 0, 255);
// Convert byte buffer to string
string stringData = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
...
// Kill original sever and create new wait server
pipeServer.Close();
pipeServer = null;
pipeServer = new NamedPipeServerStream(_pipeName, PipeDirection.In,
-1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
// Recursively wait for the connection again and again....
pipeServer.BeginWaitForConnection(
new AsyncCallback(WaitForConnectionCallBack), pipeServer);
catch
...
异步发送方法 [PipeClient 类]
class PipeClient
public void Send(string SendStr, string PipeName, int TimeOut = 1000)
try
NamedPipeClientStream pipeStream = new NamedPipeClientStream
(".", PipeName, PipeDirection.Out, PipeOptions.Asynchronous);
// The connect function will indefinitely wait for the pipe to become available
// If that is not acceptable specify a maximum waiting time (in ms)
pipeStream.Connect(TimeOut);
byte[] _buffer = Encoding.UTF8.GetBytes(SendStr);
pipeStream.BeginWrite
(_buffer, 0, _buffer.Length, new AsyncCallback(AsyncSend), pipeStream);
catch (TimeoutException oEX)
...
private void AsyncSend(IAsyncResult iar)
try
// Get the pipe
NamedPipeClientStream pipeStream = (NamedPipeClientStream)iar.AsyncState;
// End the write
pipeStream.EndWrite(iar);
pipeStream.Flush();
pipeStream.Close();
pipeStream.Dispose();
catch (Exception oEX)
...
我有两个 WinForms 应用程序:服务器只有 Listen 按钮(点击结果在 Listen 方法调用中),客户端有 textBox 用于文本输入和 发送 按钮(点击结果在 Send 方法调用中)。
我执行以下操作:
-
启动服务器应用程序的多个副本(结果 - 创建多个具有相同管道名称的 NamedPipeServerStream 实例)
点击每个按钮中的收听按钮
启动客户端应用程序
点击发送按钮
这导致只有一个服务器应用程序(那个,其侦听按钮首先被点击)接收消息。如果我再次单击 Send 按钮 - 第二次单击的服务器应用程序会收到消息。因此,实例按其上的 Listen 按钮的顺序接收消息并循环重复(但我不能 100% 确定这样的顺序 在所有条件下都相同 )。
这种行为对我来说很奇怪:我希望所有实例同时收到消息。
有人能解释一下为什么会这样吗?
如何通过单击发送按钮向所有实例发送消息?
【问题讨论】:
【参考方案1】:所以我终于找到了一个解决方案(不确定它是否最佳 - 但它正在工作)。它基于使用 NamedPipeClientStream.NumberOfServerInstances。
public void Send(string SendStr, string PipeName, int TimeOut = 1000)
try
NamedPipeClientStream pipeStream = new NamedPipeClientStream
(".", PipeName, PipeDirection.Out, PipeOptions.Asynchronous);
// The connect function will indefinitely wait for the pipe to become available
// If that is not acceptable specify a maximum waiting time (in ms)
pipeStream.Connect(TimeOut);
int _serverCount = pipeStream.NumberOfServerInstances;
byte[] _buffer = Encoding.UTF8.GetBytes(SendStr);
pipeStream.BeginWrite(_buffer, 0, _buffer.Length, new AsyncCallback(AsyncSend), pipeStream);
//there is more than 1 server present
for (int i = 1; i < _serverCount; i++)
//create another client copy and use it
NamedPipeClientStream pipeStream2 = new NamedPipeClientStream
(".", PipeName, PipeDirection.Out, PipeOptions.Asynchronous);
pipeStream2.Connect(TimeOut);
byte[] buffer2 = Encoding.UTF8.GetBytes(SendStr);
pipeStream2.BeginWrite(buffer2, 0, buffer2.Length, AsyncSend, pipeStream2);
catch (TimeoutException oEX)
...
请注意,此代码无法处理 NumberOfServerInstances 在循环运行时发生变化的情况(服务器实例突然关闭等)
顺便说一句不知道为什么 MSDN 建议使用
// Kill original sever and create new wait server
pipeServer.Close();
pipeServer = null;
pipeServer = new NamedPipeServerStream(_pipeName, PipeDirection.In,
-1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
// Recursively wait for the connection again and again....
pipeServer.BeginWaitForConnection(
new AsyncCallback(WaitForConnectionCallBack), pipeServer);
相反,我只是简单地断开了当前客户端的连接
pipeServer.Disconnect();
// Recursively wait for the connection again and again....
pipeServer.BeginWaitForConnection(
new AsyncCallback(WaitForConnectionCallBack), pipeServer);
它对我也一样。
【讨论】:
我不是专家,但我猜pipeServer = null;
逻辑是试图“帮助”垃圾收集器。但是,由于它实现了 IDisposable,因此“使用”块可能更有用。以上是关于多个管道服务器实例的异步 NamedPipes的主要内容,如果未能解决你的问题,请参考以下文章
如果客户端和服务器在不同的机器上,则无法在 NamedPipes 中模拟权限
Linux进程间通信实例(pipeshared memorysocket)