命名管道服务器读取超时

发布于 2024-11-23 15:18:43 字数 1966 浏览 1 评论 0原文

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

自:
1) NamedPipeServerStream 不支持 Stream.ReadTimeout
2) Abort() 或 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读取操作的超时呢?

When using C# NamedPipeServerStream, in case a client doesn't send any message-end-pattern (like \r\n when server reads with ReadLine()) NamedPipeServerStream Read methods will wait forever and no Abort() or Interupt() methods will work on that thread.

Since:
1) Stream.ReadTimeout not supported for NamedPipeServerStream
2) Abort() or Interupt() doesn't work on thread
3) NamedPipeServerStream.Disconnect() nether work
It is unclear, how to setup timeout on NamedPipeServerStream read operations?


Let me introduce an example. The specification of IPC we have require an exchange of \0-terminated strings. A client sends message, the server processes the message and as 'a must' sends a response.
If the client doesn't send \0 in the end (client is not ours so we can't guarantee correctness of its working), the Read method will wait forever and client (since we don't control it) may wait forever for a response too.

Next is a simplified example of an implementation:

    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]);
        }
    }

So how to set timeout on NamedPipeServerStream read operations?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

三岁铭 2024-11-30 15:18:44

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

更新:要实现超时,请使用异步 I/O (Stream.BeginRead)。 StreamReader 不直接支持此功能。如果您绝对必须使用它,请编写一个包装器流,它将根据底层流上的 BeginRead 实现 Read 并支持超时、取消等。

Since you are running the pipe in message mode, you should first read the whole message into a byte[] buffer or a memory stream and then decide whether it's valid and decode it. Pipe messages have a definite length. It cannot be retrieved explicitly, but it shows up when you are reading from a message-mode pipe. Win32 ReadFile fails with ERROR_MORE_DATA if there still are unread bytes in the message, then it returns TRUE to indicate that the message is over. After this, a call to ReadFile will block until a new message is available. StreamReader naturally doesn't know any of this and blocks your thread.

Update: to implement timeouts, use asynchronous I/O (Stream.BeginRead). StreamReader does not support this directly. If you absolutely must use it, write a wrapper stream which will implement Read in terms of BeginRead on the underlying stream and support timeouts, cancellation etc.

○愚か者の日 2024-11-30 15:18:44

尝试将 NamedPipeServerStream.ReadMode 和/或 .TransmissionMode 设置为 Byte。
无论这些如何,您都应该将可用的 BeginRead / EndRead 方法与 NamedPipeServerStream 一起使用。
这样你就可以自己实现超时逻辑了。

Try setting NamedPipeServerStream.ReadMode and/or .TransmissionMode to Byte.
Regardless of these you should use the available BeginRead / EndRead methods with NamedPipeServerStream.
This way you can implement the timeout logic yourself.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文