简体   繁体   English

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

[英]named pipe stream example not showing the result

I'm new to pipe stream and tried to practice. 我是管道流的新手,并尝试练习。 I've written the following two projects and I can't see the result (which I wrote within the server project) from the client project. 我已经编写了以下两个项目,但看不到客户端项目的结果(我在服务器项目中编写的结果)。 Here's the first project: 这是第一个项目:

using (NamedPipeServerStream namedPipeServer = new NamedPipeServerStream("test-pipe", PipeDirection.InOut, 1, PipeTransmissionMode.Message))
{
    byte[] bytes = Encoding.Default.GetBytes("Hello, it's me!\n");
    namedPipeServer.WaitForConnection();
    Console.WriteLine("A client has connected!");
    namedPipeServer.Write(bytes, 0, bytes.Length);
}

Here's the second project: 这是第二个项目:

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

What's wrong with this? 这怎么了

Thanks 谢谢

The client doesn't receive any message from the server, because namedPipeClient.IsMessageComplete must be called after read operation. 客户端没有从服务器收到任何消息,因为读取操作之后必须调用namedPipeClient.IsMessageComplete See PipeStream.IsMessageComplete on docs: 请参阅文档上的PipeStream.IsMessageComplete

Gets a value indicating whether there is more data in the message returned from the most recent read operation . 获取一个值,该值指示从最近读取操作返回的消息中是否还有更多数据。

Otherwise namedPipeClient.IsMessageComplete returns true and code inside while -loop is not executed. 否则namedPipeClient.IsMessageComplete返回true内部和代码while -loop不执行。 So you have to rewrite while loop to do-while loop to ensure, that read operation occurs before namedPipeClient.IsMessageComplete is tested. 因此,您必须将while循环重写为do-while循环,以确保在测试namedPipeClient.IsMessageComplete之前发生读取操作。

But there are more problems, see comments for explanations: 但是还有更多问题,请参阅注释以获取解释:

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

EDIT: 编辑:

When named pipe is in the PipeTransmissionMode.Message mode, every call of NamedPipeServerStream.Write() on the server sends data through the pipe as an individual message. 当命名管道处于PipeTransmissionMode.Message模式时,服务器上的NamedPipeServerStream.Write()每次调用都会通过管道将数据作为单独的消息发送。 Client can then receive these messages separated from each other (as opposed to PipeTransmissionMode.Byte mode, where client receives just single continuous stream of bytes, no matter how many writes server performed using NamedPipeServerStream.Write() ). 然后,客户端可以接收彼此分离的这些消息(与PipeTransmissionMode.Byte模式相反,在PipeTransmissionMode.Byte模式下,客户端仅接收单个连续的字节流,而不管使用NamedPipeServerStream.Write()执行多少次写入服务器)。

When client reads data from pipe ( namedPipeClient.Read() ), method is allowed to return less data then requested (for example when there is not enough space in the receiving buffer to store the whole message, or message is shorter then the requested number of bytes), see docs . 当客户端从管道读取数据( namedPipeClient.Read() )时,允许方法返回较少的数据然后再请求(例如,当接收缓冲区中没有足够的空间来存储整个消息时,或者消息短于请求的数量时)的字节数),请参阅docs

Returns the total number of bytes that are read into buffer. 返回读入缓冲区的字节总数。 This might be less than the number of bytes requested if that number of bytes is not currently available, or 0 if the end of the stream is reached. 如果该字节数当前不可用,则该数目可能小于所请求的字节数;如果到达流的末尾,则该数目可能小于 0。

You can then use namedPipeClient.IsMessageComplete and readCount to detect this. 然后,您可以使用namedPipeClient.IsMessageCompletereadCount进行检测。 Let me explain it on some example: Imagine that server sends message ABCDEFGHIJKL to the client, encoded to byte array as { 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76 } . 让我在一个示例中进行解释:假设服务器向客户端发送消息ABCDEFGHIJKL ,并编码为字节数组为{ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76 } This message has length of 12 bytes, thus it does not fit to your receiving buffer ( readBytes ) which is 5 bytes long. 该消息的长度为12个字节,因此不适合5个字节长的接收缓冲区( readBytes )。 So when client reads from pipe for the first time using namedPipeClient.Read() , receiving buffer will contain just first 5 bytes ( { 65, 66, 67, 68, 69 } corresponding to ABCDE ) of the message. 因此,当客户端首次使用namedPipeClient.Read()从管道读取消息时,接收缓冲区将仅包含消息的前5个字节(与ABCDE对应的{ 65, 66, 67, 68, 69 } namedPipeClient.Read() { 65, 66, 67, 68, 69 } )。 And this is where namedPipeClient.IsMessageComplete will help us, because it will return false indicating that we didn't receive complete message, there are still some bytes left and we should continue reading. 这就是namedPipeClient.IsMessageComplete会为我们提供帮助的地方,因为它将返回false指示我们没有收到完整的消息,仍然还有一些字节,我们应该继续阅读。

The second read from the pipe will be similar, we will read second part of the message ( { 70, 71, 72, 73, 74 } corresponding to FGHIJ ), namedPipeClient.IsMessageComplete is still false indicating incomplete message. 从管道的第二次读取将是类似的,我们将读取消息的第二部分(与FGHIJ对应的{ 70, 71, 72, 73, 74 } ), namedPipeClient.IsMessageComplete仍然为false指示消息不完整。

When third read from the pipe comletes, only 2 remaining bytes ( { 75, 76 } corresponding to KL ) will be read, but our buffer is still 5 bytes long, so it will look like this: ( { 75, 76, 72, 73, 74 } corresponding to KLHIJ ). 当从管道完成中第三次读取时,将仅读取剩余的2个字节(与KL对应的{ 75, 76 } ),但是我们的缓冲区仍为5个字节长,因此它将如下所示:( { 75, 76, 72, 73, 74 }对应于KLHIJ )。 Values 72, 73, 74 are still there from previous iteration of the loop. 循环的先前迭代中的值72, 73, 74仍然存在。 And now it is important to store value returned from namedPipeClient.Read() to the readCount variable. 现在,重要的是将从namedPipeClient.Read()返回的值存储到readCount变量。 It will contain value 2, indicating that only 2 bytes of the bytesRead buffer are valid and the remaining bytes should be ignored. 它将包含值2,指示bytesRead缓冲区中只有2个字节有效,其余字节应忽略。

Try to user StreamReader for reading messages from both pipes. 尝试使用StreamReader从两个管道读取消息。 Server: 服务器:

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

Client: 客户:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM