客户端不会收到来自服务器的任何消息,因为namedPipeClient.IsMessageComplete
必须在读取操作后调用。请参阅文档上的PipeStream.IsMessageComplete:
获取一个值,该值指示从最近的读取操作返回的消息中是否有更多数据。
否则namedPipeClient.IsMessageComplete
返回true
并且while
-loop 内的代码不会被执行。因此,您必须重写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()
,允许方法返回少于请求的数据(例如,当接收缓冲区中没有足够的空间来存储整个消息时,或者消息比请求的字节数短),请参阅文档。
返回读入缓冲区的总字节数。如果该字节数当前不可用,则这可能小于请求的字节数,或者如果到达流的末尾,则为 0。
然后,您可以使用namedPipeClient.IsMessageComplete
andreadCount
来检测它。让我用一个例子来解释一下:想象一下服务器向ABCDEFGHIJKL
客户端发送消息,编码为字节数组{ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76 }
。此消息的长度为 12 个字节,因此它不适合您readBytes
的 5 个字节长的接收缓冲区 ( )。因此,当客户端第一次使用 读取管道时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 个字节有效,其余字节应被忽略。