2011-07-15 36 views
7

当使用C#NamedPipeServerStream时,如果客户端不发送任何消息结束模式(例如服务器使用ReadLine()读取时的\ r \ n)NamedPipeServerStream读取方法将永远等待并且不中止()或Interupt()方法将在该线程上工作。命名管道服务器读取超时

时间:
1)Stream.ReadTimeout不支持NamedPipeServerStream
2)中止()或Interupt()上螺纹
3不工作)NamedPipeServerStream.Disconnect()阴工作
它是不明,如何在NamedPipeServerStream读取操作上设置超时?


让我来介绍一个例子。 IPC的规范我们要求交换\ 0终止的字符串。客户端发送消息,服务器处理消息并且'必须'发送响应。 如果客户端最终没有发送\ 0(客户端不是我们的,所以我们不能保证其工作的正确性),Read方法将永远等待,客户端(因为我们不控制它)可能会永远等待作为回应。

接下来是实现的一个简单的例子:

public void RestartServer() 
    { 
     _pipeServerThread.Interrupt(); //doesn't affect Read wait 
     _pipeServerThread.Abort();  //doesn't affect Read wait 
    } 

    private void PipeServerRun(object o) //runs on _pipeServerThread 
    { 
     _pipeServer = new NamedPipeServerStream(_pipeName, InOut, 100, 
         PipeTransmissionMode.Message, PipeOptions.WriteThrough); 
     //_pipeServer.ReadTimeout = 100; //System.InvalidOperationException: Timeouts are not supporte d on this stream. 

     // Wait for a client to connect 
     while (true) 
     { 
      _pipeServer.WaitForConnection(); 
      string request = ReadPipeString(); 
      //... process request, send response and disconnect 
     } 
    } 

    /// <summary> 
    /// Read a \0 terminated string from the pipe 
    /// </summary> 
    private string ReadPipeString() 
    { 
     StringBuilder builder = new StringBuilder(); 
     var streamReader = new StreamReader(_pipeServer); 

     while (true) 
     { 
      //read next byte 
      char[] chars = new char[1]; 
      streamReader.Read(chars, 0, 1); // <- This will wait forever if no \0 and no more data from client 

      if (chars[0] == '\0') return builder.ToString(); 
      builder.Append(chars[0]); 
     } 
    } 

那么如何设置超时的NamedPipeServerStream读取操作?

回答

2

既然你正在运行的消息模式的管道,你应该先阅读整个消息到byte[]缓存或内存流和然后决定其是否有效,并对其进行解码。管道消息具有确定的长度。它不能被明确地检索,但是当你从消息模式管道读取时它会显示出来。如果消息中仍有未读字节,则Win32 ReadFile将失败,并返回ERROR_MORE_DATA,则返回TRUE以指示消息已结束。在此之后,呼叫ReadFile将阻止,直到有新消息可用。 StreamReader自然不知道这一点,并阻止你的线程。

更新:执行超时,使用异步I/O(Stream.BeginRead)。 StreamReader不直接支持。如果你绝对必须使用它,写一个包装流,这将在BeginRead方面实现Read底层流和支持超时取消等

+0

谢谢,但不幸的是,这不是我的问题的答案。 C#NamedPipeServerStream具有IsMessageComplete标志,我相信它依赖于ERROR_MORE_DATA员工。但它恰好在消息的真实结束之前设置为真。这是我们首先检查的其中一个。如果客户端使用TransactNamedPipe看起来像它的工作,但是当在WinApi中使用C#NamedPipeClient或Write函数时 - 在消息完成之前可以将IsMessageComplete设置为true。我认为这又是因为发件人的流属性。 – MajesticRa

+0

是的,但是为什么在消息模式下运行管道呢?在消息模式下,为每个Win32'Write'调用创建一条管道消息。如果你的客户不遵守这个约定,消息模式是毫无意义的。 (顺便说一句,客户端是否将管道的客户端设置为消息模式?) –

+1

不幸的是,这个世界并不完美,我只是有了规范。 我们的测试客户端处于消息模式。但我们无法保证现有客户的这一点。 看起来BeginRead也有问题,但我仍然试验它。 – MajesticRa

1

尝试NamedPipeServerStream.ReadMode和/或.TransmissionMode设置为字节。 无论如何,您应该在NamedPipeServerStream中使用可用的BeginRead/EndRead方法。 这样你可以自己实现超时逻辑。