命名管道意外结果

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" 你的代码,但实际上它没有解决任何问题,只是把你的问题放在下面地毯。