在进程运行时以交互方式读取重定向的标准输出

时间:2015-04-08 01:37:35

标签: c# .net c#-4.0 asynchronous cmd

我正在为C#中的Windows开发类似远程shell的东西。我有一个NetworkStream设置,以及一个命令解释器实例的Process包装器。问题是,我无法从标准输出和标准错误中读取没有搞乱的东西。我的远程部分代码是这样的:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Matt_Damon_Remote_Shell
{
    class RemoteEnd
    {
        public System.Diagnostics.Process commandHost
        {
            get;
            set;
        }

        TcpListener listener;
        TcpClient client;

        NetworkStream netStream;
        StreamReader netStreamReader;
        StreamWriter netStreamWriter;

        StreamReader outputReader;
        StreamReader errorReader;


        public RemoteEnd()
        {
            initStream();
            initProcess();
        }

        public void receive()
        {
            while (true)
            {
                netStreamWriter.Write(readOutput());
                netStreamWriter.Write(readError());
                netStreamWriter.Flush();
                string next = getNextCommand();
                Console.WriteLine("Remote received: " + next);
                runCommand(next);
            }

        }

        private void initStream()
        {
            listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 666);
            waitForConnect();
            netStream = client.GetStream();
            netStreamReader = new StreamReader(netStream);
            netStreamWriter = new StreamWriter(netStream);
        }

        private void waitForConnect()
        {
            try
            {
                listener.Start();
            }
            catch (SocketException e)
            {
                Console.WriteLine(e.ToString());
            }
            client = listener.AcceptTcpClient();
        }

        private void initProcess()
        {
            commandHost = new System.Diagnostics.Process();
            //Init process
            commandHost.StartInfo.RedirectStandardInput = true;
            commandHost.StartInfo.RedirectStandardOutput = true;
            commandHost.StartInfo.RedirectStandardError = true;
            commandHost.StartInfo.UseShellExecute = false;
            commandHost.StartInfo.CreateNoWindow = true;
            commandHost.StartInfo.FileName = "cmd.exe";
            commandHost.Start();
            outputReader = new StreamReader(commandHost.StandardOutput.BaseStream);
            errorReader = new StreamReader(commandHost.StandardError.BaseStream);
        }

        private string readOutput()
        {
           //Various implementations described below
        }

        private string readError()
        {
            //Various implementations described below
        }

        private void runCommand(string command)
        {
            if (command == "exit") //this handles the exit function, which doesn't work somehow
            {
                commandHost.Kill(); 
                return;
            }
            commandHost.StandardInput.WriteLine(command);
        }

        private string getNextCommand()
        {
            if (netStream.CanRead)
            {
                return netStreamReader.ReadLine();
            }
            else
            {
                return null;
            }
        }
    }
}

首先,我试图异步地抓住它,但它回复了数据的发送。如果有足够的时间,它会把它全部发回去,但我无法通过NetworkStream发送所有内容。如果我刚刚运行程序,它什么都没发回去。如果我花时间添加断点并查看代码,它通常会返回一两行。我无法正确地同步事件处理程序,以恢复整个事情。我也试过同步阅读,但无论我尝试了什么,无论是ReadLine()ReadBlock()还是Read(),它都会阻止我的程序,我无法超越标准cmd启动消息。我知道当我读取它们时,流已经结束了,调试器显示了一个非公共字符缓冲区,最后只有空字节。但是,上述所有方法都会阻止,大概是这个过程被关闭了。在我的情况下我无法做到这一点,因为流程必须保持活跃以维护一致的工作目录和类似的东西。在我的情况下是否有一种非阻塞的同步读取方式,或者我是否必须找到适当的异步读取方法?

0 个答案:

没有答案