命名管道意外结果

时间:2018-03-26 17:52:22

标签: c# named-pipes

有一个简单的命名管道服务器:

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

            } 


        }
    }

但由于某种原因,只有第一个命令正在完成。 例如,如果我输入&#39; Y&#39;得到输出&#39; Y&#39;然后当N&#39; N&#39; N&#39; N&#39;输入什么都没有来自服务器。 需要让它连续工作。 谢谢。

2 个答案:

答案 0 :(得分:1)

那是因为在您的客户端中您在while循环之外定义StreamReader reader = new StreamReader(client);,所以在读者点击最后一行的第一次迭代中,底层流永远不会被重置,所以reader.Peek() >= 0对后续调用产生错误。

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

答案 1 :(得分:0)

使用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(包括已接受的答案)将失败,只读一行(在后续输入中,如#34; N&#34;,将再次显示任何内容,只是像现在一样)。因此,使用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循环,因为其他答案建议也不需要,它看起来像是&#34;修复&#34;你的代码,但实际上它并没有解决任何问题,只是将你的问题置于地毯之下。