命名管道服务器读取超时

本文关键字:读取 超时 服务器 管道 | 更新日期: 2023-09-27 18:02:32

当使用c# NamedPipeServerStream时,如果客户端没有发送任何消息结束模式(如服务器读取ReadLine()时的'r'n) NamedPipeServerStream读取方法将永远等待,并且没有Abort()或interrupt()方法将在该线程上工作。

以来

:
1)流。NamedPipeServerStream不支持ReadTimeout
2) Abort()或interrupt()在线程上不起作用
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读取操作上设置超时?

命名管道服务器读取超时

由于您正在以消息模式运行管道,因此您应该首先将整个消息读入byte[]缓冲区或内存流,然后决定它是否有效并解码它。管道消息具有确定的长度。它不能显式检索,但当您从消息模式管道读取时,它会显示出来。如果消息中仍有未读字节,则Win32 ReadFileERROR_MORE_DATA一起失败,然后返回TRUE以指示消息结束。在此之后,对ReadFile的调用将阻塞,直到有新消息可用。StreamReader自然不知道这些,阻塞你的线程。

Update:实现超时,使用异步I/O (Stream.BeginRead)。StreamReader不直接支持。如果你绝对必须使用它,写一个包装器流,它将在底层流上根据BeginRead实现Read,并支持超时,取消等。

尝试设置NamedPipeServerStream。ReadMode和/或。transmissionmode转换为Byte。无论如何,你应该使用NamedPipeServerStream的BeginRead/EndRead方法。这样,您就可以自己实现超时逻辑。