C# 中的命名管道输入输出
Posted
技术标签:
【中文标题】C# 中的命名管道输入输出【英文标题】:Named Pipe Input Output in C# 【发布时间】:2018-04-15 04:59:00 【问题描述】:我正在使用命名管道,并且对客户端和服务器之间的交互如何发生感到非常困惑。 我的服务器是一个附加了命名管道的虚拟机。我以这种方式在 C# 中创建了一个客户端流:
NamedPipeClientStream client = new NamedPipeClientStream(".", "TestPipe", PipeDirection.InOut);
假设VM提示如下:
Hello!
Do you accept (y/n): y
Text1 : 1.2.3.4
Text2 : 2.3.4.5
我基本上需要做的是,检查流读取的行是否是“你接受(y/n):”,如果匹配,则使用 Text1 将 y 写入 stream.es
,然后写入 1.2。 3.4 在流中
我面临的问题:
Hello!
之后的提示不显示任何内容。我的想法
是,它可能正在等待下一个输入。所以,而不是做
这个:
if(line.contains("Do you accept (y/n):"))
writer.writeLine("y")
我这样做了:
if(line.contains("Hello!"))
writer.writeLine("y");
这是正确的吗?如果是,则表示服务器 没有将文本推送到等待输入的缓冲区中。 所以,每次我都必须检查前一行和 将下一个预期行的输出写入写入器流?
另外,如上所述,为了将1.2.3.4
传递给Text1
,我这样做了:
if(line.contains("Do you accept (y/n):"))
writer.writeLine("1.2.3.4")
我的执行提示中出现的是:Text1 : 1111111
即。它是
只重复我通过的输入的第一个字符。为什么
这样的?我已经将AutoFlush = true
设置为我的作家流。
这里的任何指针将不胜感激!
编辑:包括sn-p
using System;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Windows;
namespace App1
static void Main(string [] args)
NamedPipeClientStream client = new NamedPipeClientStream(".", "TestPipe", PipeDirection.InOut);
while(!client.IsConnected);
Streamreader reader = new StreamReader(client);
StreamWriter writer = new StreamWriter(client);
string line = "";
writer.AutoFlush = true;
while((line = reader.readLine()) != null)
if(line.Contains("Hello!")
writer.writeLine("1.2.3.4"); // input for the next prompt
else if(line.Contains("Text1")
writer.writeLine("2.3.4.5"); // input for next prompt of Text2
writer.Flush();
writer.WaitForPipeDrain();
上面是正确的方式吗? 此外,有时管道读取器会丢失数据。就像它显示 Tet1 而不是 Text1。为什么会这样?
【问题讨论】:
听起来有点太笼统了,到底是什么问题? @3vts 第一个问题就是上面提到的第2点。是否预计提示符处的数据(如 Text1: 或 Text2:) 在收到输入之前不会被服务器推送到缓冲区中,这就是我无法读取它的原因? 然后第二个问题就是上面提到的第3点,为什么如果我通过1.2.3.4,我只看到1111111。 您必须编辑您的问题以包含您拥有的源代码。请记住发布MCVE,它只显示您的问题。 @Progman 已编辑。 【参考方案1】:您有这样的语句:while(!client.IsConnected);
,这会导致客户端在继续之前等待连接。但是,客户端从不尝试连接 (client.Connect();
),因此您可能会一直等待。将该行替换为 if (!client.IsConnected) client.Connect();
以使其正常工作。
除此之外,根据 cmets,如果不知道您的服务器端代码是什么样的,就很难说客户端应该发送什么;因为双方正在进行脚本对话。
以下是一些工作服务器和客户端代码的示例,用于说明如何执行此对话:
启动客户端和服务器的代码:
static void Main()
var server = Task.Factory.StartNew(() => RunServer());
var client = Task.Factory.StartNew(() => RunClient());
Task.WaitAll(server, client);
Console.WriteLine("Done");
客户端代码:
static void RunClient()
using (var pipeClient = new NamedPipeClientStream(".", "TestPipe", PipeDirection.InOut))
Console.WriteLine("Client is waiting to connect");
if(!pipeClient.IsConnected)pipeClient.Connect();
Console.WriteLine("Client is connected");
using (var reader = new StreamReader(pipeClient))
using (var writer = new StreamWriter(pipeClient))
var running = true;
while(running)
Console.WriteLine("Client is waiting for input");
var message = reader.ReadLine();
if (message != null)
Console.WriteLine("Client: Recieved from server 0", message);
switch (message)
case "Do you accept (y/n):":
writer.WriteLine("y");
writer.WriteLine("quit");
writer.Flush();
break;
case "quit":
running = false;
break;
Console.WriteLine("Client Quits");
服务器代码:
static void RunServer()
using (var pipeServer = new NamedPipeServerStream("TestPipe", PipeDirection.InOut))
using (var reader = new StreamReader(pipeServer))
using (var writer = new StreamWriter(pipeServer))
var running = true;
Console.WriteLine("Server is waiting for a client");
pipeServer.WaitForConnection();
Console.WriteLine("Server has connection from client");
Console.WriteLine("Server: Saying Hi");
writer.WriteLine("Hello!");
Console.WriteLine("Server: Prompting for Input");
writer.WriteLine("Do you accept (y/n):");
writer.Flush();
while(running)
pipeServer.WaitForPipeDrain();
var message = reader.ReadLine();
Console.WriteLine("Server: Recieved from client 0", message);
if (message.Equals("quit"))
writer.WriteLine("quit");
running = false;
Console.WriteLine("Server Quits");
更新
修改代码以读取字符而不是行;所以我们不必等待换行符才能看到服务器的消息。
//using System.Threading.Tasks;
//using System.IO.Pipes;
static void Main()
var server = Task.Factory.StartNew(() => RunServer());
var client = Task.Factory.StartNew(() => RunClient());
Task.WaitAll(server, client);
Console.WriteLine("Done");
static void RunClient()
using (var pipeClient = new NamedPipeClientStream(".", "TestPipe", PipeDirection.InOut))
Console.WriteLine("Client is waiting to connect");
if(!pipeClient.IsConnected)pipeClient.Connect();
Console.WriteLine("Client is connected");
using (var reader = new StreamReader(pipeClient))
using (var writer = new StreamWriter(pipeClient))
var message = string.Empty;
var running = true;
while(running)
Console.WriteLine("Client is waiting for input");
var chr = reader.Read();
if (chr >= 32)
message = message + (char)chr;
Console.WriteLine("Client: Recieved from server 0", message);
switch (message)
case "Do you accept (y/n):":
writer.WriteLine("y");
writer.WriteLine("quit");
writer.Flush();
break;
case "quit":
running = false;
break;
else
message = string.Empty;
Console.WriteLine("Client: New Line Received from Server");
Console.WriteLine("Client Quits");
static void RunServer()
using (var pipeServer = new NamedPipeServerStream("TestPipe", PipeDirection.InOut))
using (var reader = new StreamReader(pipeServer))
using (var writer = new StreamWriter(pipeServer))
var running = true;
Console.WriteLine("Server is waiting for a client");
pipeServer.WaitForConnection();
Console.WriteLine("Server has connection from client");
Console.WriteLine("Server: Saying Hi");
writer.WriteLine("Hello!");
Console.WriteLine("Server: Prompting for Input");
writer.Write("Do you accept (y/n):"); //NB: This is a write, not a write line!
writer.Flush();
while(running)
pipeServer.WaitForPipeDrain();
var message = reader.ReadLine();
Console.WriteLine("Server: Recieved from client 0", message);
switch (message)
case "quit":
writer.WriteLine("quit");
running = false;
break;
default:
writer.WriteLine("");
break;
Console.WriteLine("Server Quits");
所以你的代码应该是这样的:
int charAsInt;
var line = string.Empty;
while(((charAsInt = reader.Read()) != -1))
if (charAsInt >= 32) //is a displayable character
line = line + (char)charAsInt;
//your code to handle the lines
if(line.Contains("Hello!"))
writer.WriteLine("1.2.3.4"); // input for the next prompt
else if(line.Contains("Text1")
writer.WriteLine("2.3.4.5"); // input for next prompt of Text2
writer.Flush();
//writer.WaitForPipeDrain();
else //is a control character
if (charAsInt == 10 || charAsInt == 13) //carriage return or line feed; i.e. end of line
if (line.Length > 0)
Debug.WriteLine("Last line read was 0", line); //just so you can see info as it comes from the server
line = string.Empty;
【讨论】:
感谢您的详细回答。 Client.connect() 在我的代码中,只是忘记在上面的 sn-p 中复制它。另外,正如我提到的,我的服务器是我使用 hyper-v 设置的虚拟机。然后我已将命名管道与此服务器相连。因此,在我的情况下,将没有服务器代码。如果我错了,请告诉我。 不用担心。当您说服务器没有代码时,您在与什么通信;即,如果服务器代码不是您自己编写的,大概您正在连接一些已知的服务......那是什么服务/这里的服务器在扮演什么角色/您的客户试图与之交谈?即,如果它不是你写的东西,我们需要找到该服务的文档,以便我们知道它期望如何交互。 想象一下你在 Windows 机器上。假设您使用 Hyper-v 使用您拥有的 VHDK 创建了一个 VM。现在你去给它附加一个命名管道。现在,您使用 putty 建立串行通信。因此,无论 VM 串行端口上的数据如何,都将在 Putty 的会话窗口中看到。所以,我不需要为服务器编写任何代码。我希望这能进一步澄清问题。 所以,现在在这种情况下,假设VM控制台端口上的数据是“Hello”,我上面提到的客户端代码完美地读取了这一点。但是假设下一行显示“text1: ”客户端代码不显示,甚至 text1:。但是如果作者的缓冲区中已经有输入,客户端代码会显示 text1: 。这令人困惑,为什么会这样 对不起@user3552407,我不确定我是否理解这个问题(或者更确切地说,我认为我明白了这个问题,但对它的上下文了解不够多,无法发表评论)......你的目标是什么;即你为什么首先连接到这个命名管道;这可能会给我提供我所追求的上下文的线索......以上是关于C# 中的命名管道输入输出的主要内容,如果未能解决你的问题,请参考以下文章
二.编写第一个c#程序(注释,命名空间,类,Main方法,标识符,关键字,输入,输出语句,)