I'm using code from this article with only difference that maxNumberOfServerInstances is set to -1 (number of server instances with the same pipe name is limited only by system resources) in NamedPipeServerStream constructor
Async Listen Method [Listen Server Class]:
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
{ ... }
}
}
Async Send Method [PipeClient Class]
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)
{ ... }
}
}
And I have two WinForms applications: server only have Listen button (clicking results in Listen method call), client has textBox for text input and Send button (clicking results in Send method call).
I do the following:
- start multiple copies of server application (as the result - multiple instances of NamedPipeServerStream with the same pipe name are created)
- click Listen button in each of them
- start client application
- click Send button
That results in receiving message by only one server application (that one, whose Listen button was clicked first). If I click Send button one more time - message is received by second-clicked server application. So instances receive messages in order of pressing Listen button on them and that repeats in cycle (but I'm not 100% sure that such order will be the same under all conditions).
Such behavior is strange for me: I've expected message to be received by all instances at the same time.
Could someone explain me why it is happening in such way?
How can I deliver message to all instaces with one Send button click?
So finally I've found a solution (don't sure it's optimal - but it's working). It is based on using NamedPipeClientStream.NumberOfServerInstances.
Note that this code doensn't handle situation when NumberOfServerInstances changes while cycle is running (sudden server instance closing, etc.)
BTW Don't have any idea why MSDN suggests to use
Instead I've tested simply disconnecting current client
and it worked for me the same way.