【问题标题】:Async NamedPipes in case of multiple pipe server instances多个管道服务器实例的异步 NamedPipes
【发布时间】:2014-07-11 15:32:57
【问题描述】:

我正在使用来自 this article 的代码,唯一的区别是 ma​​xNumberOfServerInstances 设置为 -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 方法调用中)。

我执行以下操作:

  1. 启动服务器应用程序的多个副本(结果 - 创建多个具有相同管道名称的 NamedPipeServerStream 实例)
  2. 点击每个按钮中的收听按钮
  3. 启动客户端应用程序
  4. 点击发送按钮

这导致只有一个服务器应用程序(那个,其侦听按钮首先被点击)接收消息。如果我再次单击 Send 按钮 - 第二次单击的服务器应用程序会收到消息。因此,实例按其上的 Listen 按钮的顺序接收消息并循环重复(但我不能 100% 确定这样的顺序 在所有条件下都相同 )。

这种行为对我来说很奇怪:我希望所有实例同时收到消息

有人能解释一下为什么会这样吗?

如何通过单击发送按钮向所有实例发送消息?

【问题讨论】:

    标签: c# .net asynchronous named-pipes


    【解决方案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,因此“使用”块可能更有用。
    猜你喜欢
    • 2013-07-29
    • 1970-01-01
    • 2017-06-03
    • 2012-01-20
    • 1970-01-01
    • 2012-09-06
    • 2017-07-08
    • 1970-01-01
    相关资源
    最近更新 更多