代码之家  ›  专栏  ›  技术社区  ›  bairog

多个管道服务器实例的异步NamedPipes

  •  3
  • bairog  · 技术社区  · 10 年前

    我使用的代码来自 this article 唯一不同的是 最大服务器实例数 设置为 -1 (具有相同管道名称的服务器实例的数量仅受系统资源的限制) 命名管道服务器流 构造函数

    异步侦听方法[侦听服务器类]:

    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方法调用中的结果),客户端有文本框用于文本输入 邮寄 按钮(单击“发送方法调用”中的结果)。

    我执行以下操作:

    1. 启动服务器应用程序的多个副本(结果是 命名管道服务器流 创建具有相同管道名称的管道)
    2. 点击 每个按钮中的按钮
    3. 启动客户端应用程序
    4. 点击 邮寄 按钮

    这将导致通过 只有一个服务器应用程序 (那个 首先单击按钮)。如果我单击 邮寄 再次单击按钮-第二个单击的服务器应用程序接收到消息。因此,实例按以下顺序接收消息 按钮,循环重复(但我不能100%确定这样的顺序 在所有条件下都是一样的 ).

    这种行为对我来说很奇怪: 同时所有实例 .

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

    我如何通过一个应用程序向所有应用程序发送消息 邮寄 单击按钮?

    1 回复  |  直到 10 年前
        1
  •  2
  •   bairog    10 年前

    因此,我终于找到了一个解决方案(不确定它是最优的,但它是有效的)。它基于使用 NamedPipeClientStream.NumberOfServer实例 .

    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)
        {    ...        }
    }
    

    请注意,当NumberOfServerInstance在循环运行时发生变化时(突然关闭服务器实例等),此代码不会处理这种情况

    顺便提一下 不知道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);
    

    对我来说也是如此。