命名管道意外结果
Named Pipes unexpected result
有一个简单的命名管道服务器:
static void Main(string[] args)
{
StartServer();
Console.Read();
}
static void StartServer()
{
Task.Factory.StartNew(() =>
{
var server = new NamedPipeServerStream("TestPipes");
server.WaitForConnection();
StreamReader reader = new StreamReader(server);
StreamWriter writer = new StreamWriter(server);
while (true)
{
var line = reader.ReadLine();
if (line == "Y")
{
for (int i = 0; i < 5; i++)
writer.WriteLine(i.ToString());
writer.Flush();
}
if (line=="N")
{
for (int i = 10; i < 15; i++)
writer.WriteLine(i.ToString());
writer.Flush();
}
}
});
}
和非常简单的客户端:
static void Main(string[] args)
{
//Client
var client = new NamedPipeClientStream(Environment.MachineName, "TestPipes");
client.Connect();
Console.WriteLine($"Connection esteblished at {DateTime.Now}, you may continue");
StreamReader reader = new StreamReader(client);
StreamWriter writer = new StreamWriter(client);
while (true)
{
string input = Console.ReadLine();
if (String.IsNullOrEmpty(input)) continue;
writer.WriteLine(input);
writer.Flush();
string serverString;
while (reader.Peek() >= 0)
{
serverString = reader.ReadLine();
Console.WriteLine(serverString);
}
}
}
但由于某种原因,只有第一个命令正在完成。
例如,如果我输入 'Y' 得到输出 'Y' 然后当输入 'N' 时,服务器什么也没有。
需要让它连续工作。
谢谢你。
那是因为在您的客户端中,您在 while 循环之外定义 StreamReader reader = new StreamReader(client);
,因此在 reader 到达最后一行时的第一次迭代中,基础流永远不会被重置,所以reader.Peek() >= 0
对后续调用产生 false。
将客户端 reader 对象的声明移到 while 循环中:
var client = new NamedPipeClientStream(Environment.MachineName, "TestPipes");
client.Connect();
Console.WriteLine($"Connection esteblished at {DateTime.Now}, you may continue");
StreamWriter writer = new StreamWriter(client);
while (true)
{
StreamReader reader = new StreamReader(client);
string input = Console.ReadLine();
if (String.IsNullOrEmpty(input)) continue;
writer.WriteLine(input);
writer.Flush();
string serverString;
while (reader.Peek() >= 0)
{
serverString = reader.ReadLine();
Console.WriteLine(serverString);
}
}
使用 Peek
很少是个好主意,在这里也不是个好主意。例如,尝试像这样模拟服务器延迟:
var line = reader.ReadLine();
if (line == "Y") {
for (int i = 0; i < 5; i++) {
writer.WriteLine(i.ToString());
writer.Flush();
// delay
Thread.Sleep(100);
}
}
你会看到带有 Peek
的代码(包括已接受的答案)将失败并且只读取一行(并且在后续输入中,如 "N",将再次不显示任何内容,就像它现在)。因此,您使用 Peek
的代码不可靠,并且会在最不适当的时刻出人意料地失败。
相反,让服务器明确标记它发送的数据结束。例如,空行:
if (line == "Y") {
for (int i = 0; i < 5; i++) {
writer.WriteLine(i.ToString());
writer.Flush();
// simulate delay
Thread.Sleep(100);
}
// empty line
writer.WriteLine();
writer.Flush();
}
在客户端:
string serverString;
while (true)
{
serverString = reader.ReadLine();
if (!String.IsNullOrWhiteSpace(serverString))
Console.WriteLine(serverString);
else break;
};
此代码将可靠地工作
也不需要像其他答案建议的那样将 StreamReader
移动到内部 while 循环,它看起来像 "fixes" 你的代码,但实际上它没有解决任何问题,只是把你的问题放在下面地毯。
有一个简单的命名管道服务器:
static void Main(string[] args)
{
StartServer();
Console.Read();
}
static void StartServer()
{
Task.Factory.StartNew(() =>
{
var server = new NamedPipeServerStream("TestPipes");
server.WaitForConnection();
StreamReader reader = new StreamReader(server);
StreamWriter writer = new StreamWriter(server);
while (true)
{
var line = reader.ReadLine();
if (line == "Y")
{
for (int i = 0; i < 5; i++)
writer.WriteLine(i.ToString());
writer.Flush();
}
if (line=="N")
{
for (int i = 10; i < 15; i++)
writer.WriteLine(i.ToString());
writer.Flush();
}
}
});
}
和非常简单的客户端:
static void Main(string[] args)
{
//Client
var client = new NamedPipeClientStream(Environment.MachineName, "TestPipes");
client.Connect();
Console.WriteLine($"Connection esteblished at {DateTime.Now}, you may continue");
StreamReader reader = new StreamReader(client);
StreamWriter writer = new StreamWriter(client);
while (true)
{
string input = Console.ReadLine();
if (String.IsNullOrEmpty(input)) continue;
writer.WriteLine(input);
writer.Flush();
string serverString;
while (reader.Peek() >= 0)
{
serverString = reader.ReadLine();
Console.WriteLine(serverString);
}
}
}
但由于某种原因,只有第一个命令正在完成。 例如,如果我输入 'Y' 得到输出 'Y' 然后当输入 'N' 时,服务器什么也没有。 需要让它连续工作。 谢谢你。
那是因为在您的客户端中,您在 while 循环之外定义 StreamReader reader = new StreamReader(client);
,因此在 reader 到达最后一行时的第一次迭代中,基础流永远不会被重置,所以reader.Peek() >= 0
对后续调用产生 false。
将客户端 reader 对象的声明移到 while 循环中:
var client = new NamedPipeClientStream(Environment.MachineName, "TestPipes");
client.Connect();
Console.WriteLine($"Connection esteblished at {DateTime.Now}, you may continue");
StreamWriter writer = new StreamWriter(client);
while (true)
{
StreamReader reader = new StreamReader(client);
string input = Console.ReadLine();
if (String.IsNullOrEmpty(input)) continue;
writer.WriteLine(input);
writer.Flush();
string serverString;
while (reader.Peek() >= 0)
{
serverString = reader.ReadLine();
Console.WriteLine(serverString);
}
}
使用 Peek
很少是个好主意,在这里也不是个好主意。例如,尝试像这样模拟服务器延迟:
var line = reader.ReadLine();
if (line == "Y") {
for (int i = 0; i < 5; i++) {
writer.WriteLine(i.ToString());
writer.Flush();
// delay
Thread.Sleep(100);
}
}
你会看到带有 Peek
的代码(包括已接受的答案)将失败并且只读取一行(并且在后续输入中,如 "N",将再次不显示任何内容,就像它现在)。因此,您使用 Peek
的代码不可靠,并且会在最不适当的时刻出人意料地失败。
相反,让服务器明确标记它发送的数据结束。例如,空行:
if (line == "Y") {
for (int i = 0; i < 5; i++) {
writer.WriteLine(i.ToString());
writer.Flush();
// simulate delay
Thread.Sleep(100);
}
// empty line
writer.WriteLine();
writer.Flush();
}
在客户端:
string serverString;
while (true)
{
serverString = reader.ReadLine();
if (!String.IsNullOrWhiteSpace(serverString))
Console.WriteLine(serverString);
else break;
};
此代码将可靠地工作
也不需要像其他答案建议的那样将 StreamReader
移动到内部 while 循环,它看起来像 "fixes" 你的代码,但实际上它没有解决任何问题,只是把你的问题放在下面地毯。