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

时间:2014-07-11 15:32:57

标签: c# .net asynchronous named-pipes

我使用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方法调用中的结果),客户端有textBox用于文本输入和发送按钮(单击结果在Send方法调用中。

我执行以下操作:

  1. 启动服务器应用程序的多个副本(结果 - 创建了具有相同管道名称的 NamedPipeServerStream 的多个实例)
  2. 点击每个中的收听按钮
  3. 启动客户端应用程序
  4. 点击发送按钮
  5. 这会导致仅接收一个服务器应用程序(首先点击 Listen 按钮的那个)接收消息。如果我再次单击发送按钮 - 第二次单击的服务器应用程序会收到消息。因此,实例按顺序接收消息,按下倾听按钮,并在循环中重复(但我不能100%确定此类订单在所有情况下都是相同的)。

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

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

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

1 个答案:

答案 0 :(得分: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发生更改时,此代码不会处理这种情况。

BTW 不知道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);

它以同样的方式为我工作。