我是管道流的新手,并尝试练习。我已经编写了以下两个项目,但看不到客户端项目的结果(我在服务器项目中编写的结果)。这是第一个项目:
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}}
这怎么了?
谢谢
答案 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.IsMessageComplete
和readCount
进行检测。让我在一个示例中进行解释:假设服务器向客户端发送消息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();
}