【问题标题】:How does a .NET app redirect its own Standard Input stream?.NET 应用程序如何重定向自己的标准输入流?
【发布时间】:2016-03-07 23:30:24
【问题描述】:

我正在尝试仅使用标准输入流在 2 个 C# 应用程序之间进行双向通信 (IPC)。父应用使用Process 启动子应用,其中RedirectStandardInput = true。因此父进程能够使用childProc.StandardInput.WriteLine() 向子进程发送命令。我使用Console.OpenStandardInput() 获取的流的BeginRead()EndRead() 异步捕获这些消息。父母与孩子的沟通非常有效。我能够异步发送和接收消息。

但是当孩子尝试使用相同的代码写给父母时,.NET 会抛出这个错误:

StandardInput 尚未重定向。

那么,简单来说,.NET 应用程序如何重定向自己的标准输入流? 然后我将重定向父进程的标准输入流,以便子进程可以向它发送消息.

我的父进程是使用 .NET 4.0 x86 构建的 WinForms C# 应用程序。


编辑:这是IPC服务器的代码

internal class IPCServer {

    private Stream cmdStream;
    private byte[] cmdBuffer = new byte[4096];

    public IPCServer() {

        cmdStream = Console.OpenStandardInput(4096);

        GetNextCmd();
    }

    private void GetNextCmd() {

        // wait for next
        cmdStream.BeginRead(cmdBuffer, 0, cmdBuffer.Length, CmdRecived, null);
    }

    private void CmdRecived(IAsyncResult ar) {

        // input read asynchronously completed
        int bytesRead = 0;
        try {
            bytesRead = cmdStream.EndRead(ar);
        } catch (Exception) { }
        if (bytesRead > 0) {

            // accept cmd
            .........

            // wait for next
            GetNextCmd();
        }
    }


}

这是IPC客户端的代码

internal class IPCClient {

    private Process appProc;

    public IPCClient(Process appProcess) {

        if (!appProcess.StartInfo.RedirectStandardInput) {
            //MessageBox.Show("IPCClient : StandardInput for process '" + appProcess.ProcessName + "' has not been 'redirected'!");
            return;
        }

        appProc = appProcess;

    }

    public void SendCmd(string cmd) {

        if (appProc != null) {
            appProc.StandardInput.WriteLine(cmd);
        }

    }

}

在父进程中:

// open child app
ProcessStartInfo info = new ProcessStartInfo(childProcPath, args);
info.WorkingDirectory = childProcDir;
info.LoadUserProfile = true;
info.UseShellExecute = false;
info.RedirectStandardError = true;
info.RedirectStandardOutput = true;
info.RedirectStandardInput = true;

childProc = Process.Start(info);

// connect to app for IPC
Client = new IPCClient();
Client.Init(childProc);

// recieve cmds from app
Server = new IPCServer();
Server.OnCmdRecieved = GotCmd;
Server.Init();

在子进程中:

ownerProcess = ....

Server = new IPCServer();
Server.OnCmdRecieved = GotCmd;
Server.Init();

Client = new IPCClient();
Client.Init(ownerProcess);

【问题讨论】:

  • 显示一些代码而不是用文字描述其原理。
  • 如果可行,使用共享内存
  • I/O 重定向是一种非常乏味的 IPC 方式,不得不使用文本并与编码限制作斗争并放弃正常的控制台使用是非常有趣的。请改用命名管道。

标签: c# process stream ipc stdin


【解决方案1】:

您可以通过更方便的方式进行操作。只需让您的客户端应用程序对输入\输出重定向一无所知。 服务器应该关心重定向。

我已经使用您的技术实现了一个最简单的客户端-服务器应用程序,它演示了应该如何使用它。

客户

Client 是一个最简单的应用程序,当您输入exit 时,它会简单地回显消息并关闭:

static void Main(string[] args)
{
    string str;

    do
    {
        str = Console.ReadLine();

        Console.WriteLine("Executed: " + str);
    } while (str != "exit");
}

客户端对重定向一无所知,它只是像控制台应用程序一样工作,并将 \ 写入控制台。

服务器

服务器运行客户端进程并在其流中读取\写入。

Process p = new Process();

p.StartInfo.FileName = "ConsoleApplication1.exe";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;

p.Start();

p.StandardInput.WriteLine("a");
p.StandardInput.WriteLine("b");
p.StandardInput.WriteLine("c");
p.StandardInput.WriteLine("d");
p.StandardInput.WriteLine("exit");
p.StandardInput.WriteLine("f");

p.StandardInput.Close();

string res = p.StandardOutput.ReadToEnd();

执行此代码后,res 包含以下文本:

Executed: a
Executed: b
Executed: c
Executed: d
Executed: exit

【讨论】:

  • 不可能这样,因为客户端应用程序将与服务器异步通信。它不是请求/响应系统。
【解决方案2】:

如果子进程只是在子进程的 StandardOutput 流上使用 BeginRead()EndRead() 会怎样。应该可以!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-17
    • 2011-10-27
    • 2022-11-10
    • 2012-12-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多