【问题标题】:Named pipe hanging on read挂在读取上的命名管道
【发布时间】:2015-08-30 14:48:32
【问题描述】:

我有一个命名管道服务器。客户端发送消息,看起来没问题,但是服务器只是挂在var stringData = textReader.ReadToEnd(); 线上。

var namedPipeServerStream = new NamedPipeServerStream(_pipeName,
                        PipeDirection.In,
                        1,
                        PipeTransmissionMode.Byte,
                        PipeOptions.Asynchronous);

namedPipeServerStream.WaitForConnection();

using (var textReader = new StreamReader(namedPipeServerStream))
{
    var stringData = textReader.ReadToEnd();

    _callback(stringData);

    namedPipeServerStream.Flush();
    namedPipeServerStream.Close();
}

Thread.Sleep(1);

客户端是这样的:

public void Send(string message)
{
    var pipeStream = new NamedPipeClientStream(_serverName,
        _pipeName,
        PipeDirection.Out,
        PipeOptions.Asynchronous);

    pipeStream.Connect(_timeout);

    var buffer = UTF8.GetBytes(message);

    pipeStream.Write(buffer, 0, buffer.Length);
}

为什么会挂起?

【问题讨论】:

    标签: .net named-pipes


    【解决方案1】:

    NamedPipe 流与网络流一样,没有明确的结束,它们只是暂时“干涸”,这就是为什么您的 ReadToEnd 调用会无限期地尝试读取更多数据。

    但是,您可以在服务器端将PipeTransmissionMode 更改为Message,以使每次写入管道都被视为单独的消息,然后从流中读取,直到IsMessageComplete 返回true .例如:

    using (var namedPipeServerStream = new NamedPipeServerStream(_pipeName,
                    PipeDirection.InOut,
                    1,
                    PipeTransmissionMode.Message,
                    PipeOptions.Asynchronous))
    {
        namedPipeServerStream.WaitForConnection();
    
        MemoryStream ms = new MemoryStream();
        byte[] buffer = new byte[0x1000];
        do { ms.Write(buffer, 0, namedPipeServerStream.Read(buffer, 0, buffer.Length)); }
        while (!namedPipeServerStream.IsMessageComplete);
    
        string stringData = Encoding.UTF8.GetString(ms.ToArray());
        _callback(stringData);
    }
    
    Thread.Sleep(1);
    

    【讨论】:

    • 我对将PipeTransmissionMode 设置为Message 的确切作用有点困惑。它是否在消息之间添加了一些分隔符?
    • 我还发现处理NamedPipeClientStream 可以防止服务器挂起。
    • @BanksySan,没有分隔符,一旦与单个写入相关的所有字节都被服务器流读取,本机操作系统 API 就会为 IsMessageComplete 设置底层标志。
    • 那我猜客户端和服务端都要设置?
    • @BanksySan 不会,除非您也打算从客户端读取流,在这种情况下,您应该设置 NamedPipeClientStreamReadMode after 调用Connect.
    【解决方案2】:

    我遇到了同样的问题,我在 WRITE 端用 flush 修复了它。

    流写入后立即在客户端刷新管道,以便服务器端可以获取消息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-22
      • 1970-01-01
      • 1970-01-01
      • 2012-11-25
      • 1970-01-01
      • 2020-07-18
      相关资源
      最近更新 更多