命名管道流示例未显示结果

时间:2018-09-01 03:43:09

标签: c# namedpipeserverstream

我是管道流的新手,并尝试练习。我已经编写了以下两个项目,但看不到客户端项目的结果(我在服务器项目中编写的结果)。这是第一个项目:

using (NamedPipeClientStream namedPipeClient = new NamedPipeClientStream(".", "test-pipe", PipeDirection.InOut))
{
    namedPipeClient.Connect();
    namedPipeClient.ReadMode = PipeTransmissionMode.Message;
    string serverResponse = string.Empty;
    byte[] readBytes = new byte[5];
    while (!namedPipeClient.IsMessageComplete)
    {
        namedPipeClient.Read(readBytes, 0, readBytes.Length);
        serverResponse = Encoding.Default.GetString(readBytes);
        readBytes = new byte[5];
    }
    System.Console.WriteLine(serverResponse);
    byte[] writeBytes = Encoding.Default.GetBytes("Hello from client!\n");
    namedPipeClient.Write(writeBytes, 0, writeBytes.Length);
}

这是第二个项目:

{{1}}

这怎么了?

谢谢

2 个答案:

答案 0 :(得分:1)

客户端没有收到来自服务器的任何消息,因为namedPipeClient.IsMessageComplete必须在读取操作之后被称为 。请参阅文档上的PipeStream.IsMessageComplete

  

获取一个值,该值指示消息中是否还有更多数据   从最近的读取操作中返回

否则,namedPipeClient.IsMessageComplete返回true,并且while循环内的代码不执行。因此,您必须将while循环重写为do-while循环,以确保读取操作在测试namedPipeClient.IsMessageComplete之前发生。

但是还有更多问题,请参阅注释以获取解释:

using (NamedPipeClientStream namedPipeClient = new NamedPipeClientStream(".", "test-pipe", PipeDirection.InOut))
{
    namedPipeClient.Connect();
    namedPipeClient.ReadMode = PipeTransmissionMode.Message;

    // StringBuilder is more efficient for string concatenation
    StringBuilder serverResponse = new StringBuilder();

    byte[] readBytes = new byte[5];

    do
    {
        // You need to store number of bytes read from pipe (to readCount variable).
        // It can be less then the length of readBytes buffer, in which case
        // GetString() would decode characters beyond end of message.
        var readCount = namedPipeClient.Read(readBytes, 0, readBytes.Length);
        var readText = Encoding.Default.GetString(readBytes, 0, readCount);

        // You original code "overwrites" content of serverResponse variable instead
        // of concatenating it to the previous value. So you would receive only 
        // the last part of the server message.
        serverResponse.Append(readText);

        // It is not needed to create new buffer, you can just reuse existing buffer
        //readBytes = new byte[5];

    // IsMessageComplete is now tested after read operation
    } while (!namedPipeClient.IsMessageComplete);

    System.Console.WriteLine(serverResponse.ToString());

    // You current server implementation exits as soon as it sends message to the client
    // and does not wait for incomming message. You'll have to change server accordingly 
    // to be able to send a message back to the server.
    //byte[] writeBytes = Encoding.Default.GetBytes("Hello from client!\n");
    //namedPipeClient.Write(writeBytes, 0, writeBytes.Length);
}

编辑:

当命名管道处于PipeTransmissionMode.Message模式时,服务器上NamedPipeServerStream.Write()的每次调用都会通过管道将数据作为单独的消息发送。然后,客户端可以接收彼此分离的这些消息 (与PipeTransmissionMode.Byte模式相反,在该模式下,客户端仅接收单个连续的字节流,而不管使用NamedPipeServerStream.Write()执行多少次写入服务器)。

当客户端从管道(namedPipeClient.Read())中读取数据时,允许方法返回的数据少于请求的数据(例如,当接收缓冲区中没有足够的空间来存储整个消息时,或者消息短于请求的字节数),请参见docs

  

返回读入缓冲区的字节总数。 此   可能少于请求的字节数,如果该数量的   字节当前不可用;如果流的末尾为   到达。

然后可以使用namedPipeClient.IsMessageCompletereadCount进行检测。让我在一个示例中进行解释:假设服务器向客户端发送消息ABCDEFGHIJKL,并以{ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76 }的形式编码到字节数组。该消息的长度为12个字节,因此不适合5个字节长的接收缓冲区(readBytes)。因此,当客户端使用namedPipeClient.Read()首次从管道读取消息时,接收缓冲区将仅包含消息的前5个字节(与{ 65, 66, 67, 68, 69 }对应的ABCDE)。这就是namedPipeClient.IsMessageComplete会为我们提供帮助的地方,因为它将返回false,表明我们没有收到完整的消息,仍然还有一些字节,我们应该继续阅读。

从管道的第二次读取将类似,我们将读取消息的第二部分(与{ 70, 71, 72, 73, 74 }对应的FGHIJ),namedPipeClient.IsMessageComplete仍为false表示不完整消息。

从管道完成第三次读取时,将仅读取剩余的2个字节(与{ 75, 76 }对应的KL,但我们的缓冲区仍为5个字节长,因此如下所示:( { 75, 76, 72, 73, 74 }对应于KLHIJ)。循环的先前迭代中的值72, 73, 74仍然存在。现在,重要的是将从namedPipeClient.Read()返回的值存储到readCount变量中。它将包含值2,指示bytesRead缓冲区中只有2个字节有效,其余字节应忽略。

答案 1 :(得分:0)

尝试让用户StreamReader从两个管道读取消息。 服务器:

using (NamedPipeServerStream namedPipeServer = new NamedPipeServerStream("test-pipe", PipeDirection.InOut, 1, PipeTransmissionMode.Byte))
{
    namedPipeServer.WaitForConnection();
    Console.WriteLine("A client has connected!");

    byte[] bytes = Encoding.Default.GetBytes("Hello, it's me!\n");
    namedPipeServer.Write(bytes, 0, bytes.Length);
    namedPipeServer.WaitForPipeDrain();

    var reader = new StreamReader(namedPipeServer);
    var msg = reader.ReadLine();
    Console.WriteLine(msg);
}

客户:

using (NamedPipeClientStream namedPipeClient = new NamedPipeClientStream(".", "test-pipe", PipeDirection.InOut))
{
    namedPipeClient.Connect();

    var reader = new StreamReader(namedPipeClient);
    var msg = reader.ReadLine();
    Console.WriteLine(msg);

    byte[] writeBytes = Encoding.Default.GetBytes("Hello from client!\n");
    namedPipeClient.Write(writeBytes, 0, writeBytes.Length);
    namedPipeClient.WaitForPipeDrain();
}