C# 中的事件驱动标准输入
Event driven stdin in C#
当 stdin stream for my own process? Something like Process.OutputDataReceived 上接收到数据时,C# 是否提供事件,只有我需要 InputDataReceived 的事件。
我到处搜索,并学会了 redirect stdin->stdout, monitor output streams of spawned apps 和大量其他内容,但没有人显示收到标准输入时触发了哪个事件。除非我在 main()
.
中使用愚蠢的轮询循环
// dumb polling loop -- is this the only way? does this consume a lot of CPU?
while ((line = Console.ReadLine()) != null && line != "") {
// do work
}
此外,我需要从流中获取二进制数据,如下所示:
using (Stream stdin = Console.OpenStandardInput())
using (Stream stdout = Console.OpenStandardOutput())
{
byte[] buffer = new byte[2048];
int bytes;
while ((bytes = stdin.Read(buffer, 0, buffer.Length)) > 0) {
stdout.Write(buffer, 0, bytes);
}
}
轮询循环不会消耗太多 CPU,因为 ReadLine 会阻塞并等待。将此代码放在自己的工作线程中,并从中引发您的事件。据我所知,.NET 中没有这样的功能。
编辑:我一开始就错了。更正:
您实际上可以从 stdin 读取二进制数据,如 this SO answer 所说:
To read binary, the best approach is to use the raw input stream - here showing something like "echo" between stdin and stdout:
using (Stream stdin = Console.OpenStandardInput())
using (Stream stdout = Console.OpenStandardOutput())
{
byte[] buffer = new byte[2048];
int bytes;
while ((bytes = stdin.Read(buffer, 0, buffer.Length)) > 0) {
stdout.Write(buffer, 0, bytes);
}
}
这是一种异步方法。与 OutputDataReceived 一样,回调在换行符上运行。对于二进制,streaming to base64 可能有效。将其切换为二进制流更难,因为您不能只检查换行符。
using System.Diagnostics;
using System.Threading.Tasks;
public static void ListenToParent(Action<string> onMessageFromParent)
{
Task.Run(async () =>
{
while (true) // Loop runs only once per line received
{
var text = await Console.In.ReadLineAsync();
onMessageFromParent(text);
}
});
}
以下是我的父应用设置子进程的方式:
var child = new Process()
{
EnableRaisingEvents = true,
StartInfo =
{
FileName = ..., // .exe path
RedirectStandardOutput = true,
RedirectStandardInput = true,
UseShellExecute = false,
CreateNoWindow = true
},
};
child.Start();
child.BeginOutputReadLine();
...以及它如何向子进程发送一行:
child.StandardInput.WriteLine("Message from parent");
当 stdin stream for my own process? Something like Process.OutputDataReceived 上接收到数据时,C# 是否提供事件,只有我需要 InputDataReceived 的事件。
我到处搜索,并学会了 redirect stdin->stdout, monitor output streams of spawned apps 和大量其他内容,但没有人显示收到标准输入时触发了哪个事件。除非我在 main()
.
// dumb polling loop -- is this the only way? does this consume a lot of CPU?
while ((line = Console.ReadLine()) != null && line != "") {
// do work
}
此外,我需要从流中获取二进制数据,如下所示:
using (Stream stdin = Console.OpenStandardInput())
using (Stream stdout = Console.OpenStandardOutput())
{
byte[] buffer = new byte[2048];
int bytes;
while ((bytes = stdin.Read(buffer, 0, buffer.Length)) > 0) {
stdout.Write(buffer, 0, bytes);
}
}
轮询循环不会消耗太多 CPU,因为 ReadLine 会阻塞并等待。将此代码放在自己的工作线程中,并从中引发您的事件。据我所知,.NET 中没有这样的功能。
编辑:我一开始就错了。更正:
您实际上可以从 stdin 读取二进制数据,如 this SO answer 所说:
To read binary, the best approach is to use the raw input stream - here showing something like "echo" between stdin and stdout:
using (Stream stdin = Console.OpenStandardInput())
using (Stream stdout = Console.OpenStandardOutput())
{
byte[] buffer = new byte[2048];
int bytes;
while ((bytes = stdin.Read(buffer, 0, buffer.Length)) > 0) {
stdout.Write(buffer, 0, bytes);
}
}
这是一种异步方法。与 OutputDataReceived 一样,回调在换行符上运行。对于二进制,streaming to base64 可能有效。将其切换为二进制流更难,因为您不能只检查换行符。
using System.Diagnostics;
using System.Threading.Tasks;
public static void ListenToParent(Action<string> onMessageFromParent)
{
Task.Run(async () =>
{
while (true) // Loop runs only once per line received
{
var text = await Console.In.ReadLineAsync();
onMessageFromParent(text);
}
});
}
以下是我的父应用设置子进程的方式:
var child = new Process()
{
EnableRaisingEvents = true,
StartInfo =
{
FileName = ..., // .exe path
RedirectStandardOutput = true,
RedirectStandardInput = true,
UseShellExecute = false,
CreateNoWindow = true
},
};
child.Start();
child.BeginOutputReadLine();
...以及它如何向子进程发送一行:
child.StandardInput.WriteLine("Message from parent");