我正在为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启动消息。我知道当我读取它们时,流已经结束了,调试器显示了一个非公共字符缓冲区,最后只有空字节。但是,上述所有方法都会阻止,大概是这个过程被关闭了。在我的情况下我无法做到这一点,因为流程必须保持活跃以维护一致的工作目录和类似的东西。在我的情况下是否有一种非阻塞的同步读取方式,或者我是否必须找到适当的异步读取方法?