Межпроцессное взаимодействие между C# и Python
Я могу понять, что по этой теме было много вопросов, но ни один из них не мог решить мою проблему. Итак, здесь я представил свой код и хочу, чтобы мои ошибки были указаны здесь.
У меня есть программа, написанная на C#, которая должна вызывать исполняемый файл / файл Python. Первое требование заключается в том, что я должен передать один аргумент в файл Python через поток ввода. Это я мог сделать. Реальная проблема, с которой я сейчас сталкиваюсь, заключается в том, что мне нужно посмотреть, печатает ли мой файл python "Пожалуйста, введите аргумент_x", мне нужно прочитать этот вывод в моем коде C# и проверить, является ли он аргументом_x, а затем записать только значение аргумента в входной поток. Ниже приведены фрагменты кода для C# и Python.
Код C# выглядит следующим образом:
using System;
using System.IO;
using System.Diagnostics;
using System.ComponentModel;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
//Create a new process object
Process myProcess = new Process();
//Provide the start information for the process
myProcess.StartInfo.FileName = "python.exe";
myProcess.StartInfo.Arguments = "mytestpython.py";
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.StartInfo.RedirectStandardOutput = true;
StreamReader myStreamReader;
StreamWriter myStreamWriter;
//Invoke the process from current process
myProcess.Start();
myStreamReader = myProcess.StandardOutput;
//Read the standard output of the spawned process.
string myString = myProcess.StandardOutput.ReadToEnd();
Console.WriteLine(myString);
if (myString.Contains("argument_x"))
{
myStreamWriter = myProcess.StandardInput;
String argument = "argument_value";
myStreamWriter.WriteLine(argument);
}
myProcess.WaitForExit();
myStreamWriter.Close();
myStreamReader.Close();
myProcess.Close();
}
}
}
Программа на python в файле mytestpython.py выглядит следующим образом:
import sys
import getpass
prompt_string = "Please enter argument_x"
if sys.stdin.isatty():
reqd_arg = getpass.getpass(prompt=prompt_string)
else:
print(prompt_string)
reqd_arg = sys.stdin.readline().rstrip()
Пожалуйста, помогите мне, так как я чувствую, что правильно написал 90% кода с небольшой ошибкой где-то посередине. Заранее спасибо за помощь.
3 ответа
Когда вы делаете myProcess.StandardOutput.ReadToEnd();
, он пытается прочитать до конца стандартный вывод вашей программы на Python, то есть он будет ждать, пока программа Python завершит выполнение, и закроет свой поток стандартного вывода, чего он никогда не делает, потому что он ожидает ввода от вашей программы на C#. Это приводит к тупику.
ReadToEnd()
полезно, когда родительский процесс ожидает завершения дочернего процесса. В случае интерактивного взаимодействия процессов, вы действительно должны рассмотреть возможность использования асинхронной связи с использованием BeginOutputReadLine
проверьте документацию MSDN здесь для помощи
Я изменил код C#, чтобы принимать параметры CLI и передавать пароль в командной строке следующим образом:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.ComponentModel;
namespace Stub
{
class Program
{
static void Main(string[] args)
{
// Declare variables and initialize
string passWord = string.Empty;
string processArgs = getArguments(args); //Call getArguments method
Console.Write("Please enter the system password : ");
passWord = readPassword(); //call readPassword method
Process p = new Process();
p.StartInfo.FileName = "myexe.exe";
p.StartInfo.Arguments = processArgs;
p.StartInfo.WorkingDirectory = "my_working_directory";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
StreamWriter sw = p.StandardInput;
StreamReader sr = p.StandardOutput;
writePassword(sr, sw, "password", passWord);
sw.Close();
sr.Close();
p.WaitForExit();
p.Close();
}
static string getArguments(string[] args)
{
StringBuilder procArgs = new StringBuilder();
foreach (string arg in args)
{
procArgs.Append(arg);
procArgs.Append(" ");
}
return procArgs.ToString();
}
static void writePassword(StreamReader sr, StreamWriter sw, string keyWord, string passWord)
{
string mystring;
do
{
mystring = sr.ReadLine();
} while (!mystring.Contains(keyWord));
if (mystring.Contains(keyWord))
sw.WriteLine(passWord);
else
sw.WriteLine("\r\n");
}
static string readPassword()
{
string pass = string.Empty;
ConsoleKeyInfo key;
do
{
key = Console.ReadKey(true);
if (key.Key != ConsoleKey.Backspace)
{
pass +=key.KeyChar;
Console.Write("*");
}
else
{
if (pass.Length > 0)
{
pass = pass.Substring(0, (pass.Length - 1));
Console.Write("\b \b");
}
}
} while (key.Key != ConsoleKey.Enter);
return pass;
}
}
}
А потом просто небольшая модификация в Python:
import sys
import getpass
prompt_string = "Please enter password"
if sys.stdin.isatty():
reqd_arg = getpass.getpass(prompt=prompt_string)
else:
print(prompt_string)
sys.stdout.flush()
reqd_arg = sys.stdin.readline().rstrip()
И вуаля.. это сработало!!!