Interprocess communication between C# and Python

耗尽温柔 提交于 2019-12-22 21:44:44

问题


I can understand that there has been a lot of questions on this topic but none of them could really solve my problem. So here I have presented my code, and I want my mistakes to be pointed out here.

I have a program written in C# which shall call a python executable/file. The first requirement is that I have pass one argument to the python file via the input stream. This I could do. The real problem I am facing now is that, I have to see whether my python file is printing "Please enter argument_x", I have to read this output in my C# code and check if it is argument_x, then only write the argument value in the input stream. Below are the code snippets for C# and Python.

The C# code is as follows:

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();
      }
   }
}

The python program in mytestpython.py file looks like this:

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()

Please help me out, as I feel I have written 90% of the code correctly with a minor mistake somewhere in between. Thanks in advance for your help.


回答1:


When you do myProcess.StandardOutput.ReadToEnd();, it tries to read to the end of the stdout of your Python program, meaning it will wait for the Python program to finish executing and close its stdout stream, which it never does because it's waiting for input from your C# program. This results in a deadlock.




回答2:


ReadToEnd() is useful when the parent process waits for child process to finish. In case of interactive process communication, you should really consider using asynchronous communications using BeginOutputReadLine check the MSDN documentation here for help




回答3:


I modified the C# code to accept CLI params and to pass the password on a prompt as follows:

    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;
    }
}

}

And then just a small modification in Python as :

    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()

And voila..that worked !!!



来源:https://stackoverflow.com/questions/10940068/interprocess-communication-between-c-sharp-and-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!