Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?

Connecting Perl's STDIN and STDOUT to .Net StreamReader

by bsdz (Friar)
on Sep 03, 2008 at 11:15 UTC ( #708724=perlquestion: print w/replies, xml ) Need Help??
bsdz has asked for the wisdom of the Perl Monks concerning the following question:

Esteemed monks

I am starting a Perl process using C#'s Process class which redirects its STDIN and STDOUT to internal .Net StreamReader objects. The problem is that the Perl process appears to close its STDOUT prematurely even when it has more data to process. I am not sure if this is a .Net issue or a Perl issue. Here is my C# code: -

using System; using System.Threading; using System.Diagnostics; namespace TestPerlStdout { class Program { private static Process process; private static void ProcessStdout() { int totalBytes = 0; while (process.StandardOutput.Peek() >= 0) { char[] buffer = new char[4096]; int count = process.StandardOutput.Read(buffer, 0, buffer.Leng +th); totalBytes += count; } Console.WriteLine(String.Format("Stopped processing after {0} by +tes", totalBytes)); } static void Main(string[] args) { ProcessStartInfo si = new ProcessStartInfo(); si.FileName = "c:\\perl\\bin\\perl.exe"; si.Arguments = "-ne \"print qq($_\n)\" "; si.UseShellExecute = false; si.RedirectStandardOutput = true; si.RedirectStandardInput = true; process = Process.Start(si); ThreadStart start = new ThreadStart(ProcessStdout); Thread stdoutThread = new Thread(start); stdoutThread.Start(); while (true) { process.StandardInput.WriteLine("1"); process.StandardInput.Flush(); } } } }
On running this, the console outputs "Stopped processing after 8191 bytes". Can anyone help me with some insight to what is happening?

Replies are listed 'Best First'.
Re: Connecting Perl's STDIN and STDOUT to .Net StreamReader
by Corion (Pope) on Sep 03, 2008 at 11:27 UTC

    This sounds to me as if you are Suffering From Buffering, possibly connected with a bad use of the .Peek() method. I presume that the .Peek() method will return a false value whenver no data is available from the filehandle, that is, whenever you are reading too fast from your child. I don't see any mention of the .Peek() method in the System.Diagnostics.Process.Standardoutput Documentation, but it also mentions the buffering issues you're likely to encounter.

      The .Net Peek() method actually belongs to the StreamReader class of Which Sys.Diag.Process.Stdout is an instance of. It always returns the next char in a Stream or -1 if the Stream is closed or doesn't support Peek. I would hope otherwise it would block if the Stream is open and just empty. I will re-examine this part of the documentation.

      I am suspicious of Perl's buffering. However, when I try running a similar Perl process using Win32 command with type(cat) it works fine.

        I think Corion called it right. From the docs (my emphasis):

        The current position of the StreamReader object is not changed by Peek. The returned value is -1 if no more characters are currently available

        That suggests .Peek will return -1 when there is nothing currently available. Not when nothing more will ever become available (in a microsecond from now).

        Your fix is probabaly to use the "standard c# idiom":

        using (StreamReader sr = ... ) { string line; // Read and display lines from the file until the end +of // the file is reached. while ((line = sr.ReadLine()) != null) { ... } } }

        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
      After looking at it more closely and reading BrowserUK's message it appears that Peek does behave as you suggested. I eventually fixed it by using a blocking read instead. I.e.
      int totalBytes = 0; int count; char[] buffer = new char[4096]; while ( (count = process.StandardOutput.ReadBlock(buffer, 0, buf +fer.Length)) > 0 ) { totalBytes += count; }
      Sorry for it not being ultimately a Perl question but thanks in any case :)
Re: Connecting Perl's STDIN and STDOUT to .Net StreamReader
by moritz (Cardinal) on Sep 03, 2008 at 11:24 UTC
    This a .net question, not a perl question I think, so you're not quite a the right place. Just a wild guess:
    si.Arguments = "-ne \"print qq($_\n)\" "; si.UseShellExecute = false;
    If the shell is not used, do you even need these additional quotes? If I'd do it in perl, the arguments to system or a pipe open would be ('-ne', 'print qq($_\n)')

    Mind you I don't know any .net at all, so it might be something completely different.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://708724]
Approved by Corion
choroba knows the situation. At work, unit tests run for 30 minutes, and integration and end-to-end tests take almost one hour.

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (5)
As of 2017-03-26 22:08 GMT
Find Nodes?
    Voting Booth?
    Should Pluto Get Its Planethood Back?

    Results (315 votes). Check out past polls.