23

I have two .NET applications that talk to each other over a named pipe. Everything is great the first time through, but after the first message is sent, and the server is going to listen again, the WaitForConnection() method throws a System.IO.Exception with message Pipe is broken.
Why am I getting this exception here? This is my first time working with pipes, but a similar pattern has worked for me in the past with sockets.

Code ahoy!
Server:

using System.IO.Pipes;

static void main()
{
    var pipe = new NamedPipeServerStream("pipename", PipeDirection.In);
    while (true)
    {
        pipe.Listen();
        string str = new StreamReader(pipe).ReadToEnd();
        Console.Write("{0}", str);
    }
}

Client:

public void sendDownPipe(string str)
{
    using (var pipe = new NamedPipeClientStream(".", "pipename", PipeDirection.Out))
    {
        using (var stream = new StreamWriter(pipe))
        {
            stream.Write(str);
        }
    }
}

The first call to sendDownPipe gets the server to print the message I send just fine, but when it loops back up to listen again, it poops.

Marcus Mangelsdorf
  • 2,852
  • 1
  • 30
  • 40
  • 2
    I think the reason you are having this issue is because of the line "new StreamReader(pipe)". The scope of created stream reader is the first while loop and it is then recreated. However stream readers behavior is to close the stream they are wrapping - thus once it is out of scope it will close the pipe stream. You can try moving its declaration out of the while loop and check (P.S: I did not personally try if the code works if you do so - just wanted to add a comment rather than answer) – user3141326 Apr 07 '16 at 15:05

4 Answers4

22

I'll post my code that seems to work - I was curious since I never did anything with pipes. I didn't find the class you name for the server-side in the relevant namespace, so here's the code based on the NamedPipeServerStream. The callback stuff is just because I couldn't be bothered with two projects.

NamedPipeServerStream s = new NamedPipeServerStream("p", PipeDirection.In);
Action<NamedPipeServerStream> a = callBack;
a.BeginInvoke(s, ar => { }, null);
...
private void callBack(NamedPipeServerStream pipe)
{
  while (true)
  {
    pipe.WaitForConnection();
    StreamReader sr = new StreamReader(pipe);
    Console.WriteLine(sr.ReadToEnd());
    pipe.Disconnect();
  }
}

And the client does this:

using (var pipe = new NamedPipeClientStream(".", "p", PipeDirection.Out))
using (var stream = new StreamWriter(pipe))
{
  pipe.Connect();
  stream.Write("Hello");
}

I can repeat above block multiple times with the server running, no prob.

flq
  • 22,247
  • 8
  • 55
  • 77
  • 2
    That did the trick. I guess theres no implicit disconnect when a client falls off the other end. Thanks. –  May 22 '09 at 14:06
  • 1
    This gives me an error that the pipe isn't connected on this line: `using (var stream = new StreamWriter(pipe))` – eliah Dec 05 '11 at 21:57
  • 2
    Doesn't seem to work between processes. The pipe.Disconnect() blows up with a "Cannot access a closed pipe" – Sean Jun 29 '17 at 14:15
  • Here's what I ended up doing: https://stackoverflow.com/a/44828800/1641247 – Sean Jun 29 '17 at 15:09
  • 1
    @Sean, when your StreamWriter is disposed by the using(), the underlying pipe is closed, too. You can avoid that by creating the StreamWriter with new StreamWriter(pipe, Encoding.UTF8, -1, true). And you need to create the reader with a similar overload. – Michael Sep 20 '19 at 20:41
14

The problem for me has occurred when I would call pipe.WaitForConnection() from the server, after the client disconnected. The solution is to catch the IOException and call pipe.Disconnect(), and then call pipe.WaitForConnection() again:

while (true)
{
    try
    {
        _pipeServer.WaitForConnection();
        break;
    }
    catch (IOException)
    {
        _pipeServer.Disconnect();
        continue;
    }            
 }
John Galt
  • 141
  • 1
  • 2
0

I ran into a similar issue when I put Environment.Exit(0) at the end of my Main method, which apparently killed the entire process even though I thought the code was unreachable (because it was after a while loop waiting for a different thread to stop).

Rashi Abramson
  • 1,127
  • 8
  • 16
-3

I had the same problem - it is caused by disposing server's StreamReader by Using...End Using, which also take down NamedPipeServerStream. Solution is simply don't Using...End Using it and trust in garbage collector.

Ondřej
  • 1,645
  • 1
  • 18
  • 29
  • If you don't use ```using``` consider using ```Dispose()```. Hoping that GC will free the memory is a bad approach. – Jirka Picek Aug 05 '21 at 10:38