mtr icon indicating copy to clipboard operation
mtr copied to clipboard

Why read pipe nothing in Go, but ok in Java?HELP!!!

Open billcoding opened this issue 2 years ago • 14 comments

Go

package main

import (
	"bufio"
	"fmt"
	"os/exec"
)

func main() {
	cmd := exec.Command("mtr", "-p", "-c", "10", "www.qq.com")
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		fmt.Println(err)
	}
	if err := cmd.Start(); err != nil {
		fmt.Println(err)
	}
	go func() {
		scr := bufio.NewScanner(stdout)
		for {
			if scr.Scan() {
				fmt.Println(scr.Text())
			}
			if scr.Err() != nil {
				return
			}
		}
	}()
	if err := cmd.Wait(); err != nil {
		fmt.Println(err)
	}
}

Java

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) {
        try {
            Process p = Runtime.getRuntime().exec(new String[]{"mtr", "www.qq.com", "-p", "-c", "10"});
            try (BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
                String line;
                while ((line = input.readLine()) != null) {
                    System.out.println(line);
                }
            }
        } catch (Exception err) {
            err.printStackTrace();
        }
    }
}

billcoding avatar Sep 27 '22 08:09 billcoding

It looks like mtr got stuck on stdin in your Go program, so just open stdin and keep it opened, and you will get something in output (stdout or stderr)

yvs2014 avatar Sep 28 '22 21:09 yvs2014

Thank you very much for your comment, but I don't seem to understand what you mean, can you be more clear, thks.

billcoding avatar Sep 29 '22 09:09 billcoding

He is suspecitng that the subcommand mtr doesn't have stdin connected and that this messes something up. There should be a cmds.stdin = "/dev/null" that you can add. (but I've never written a line of "go" in my life, so you'll have to figure out the exact syntax on your own.)

rewolff avatar Sep 29 '22 10:09 rewolff

@rewolff not totally, I suppose /dev/null stdin is already present in that go code it can be emulated with mtr -p -c 10 www.qq.com </dev/null

yvs2014 avatar Sep 29 '22 13:09 yvs2014

@billcoding try this

package main

import (
        "bufio"
        "fmt"
        "os"
        "os/exec"
)

func main() {
        cmd := exec.Command("mtr", "-p", "-c", "10", "www.qq.com")
        stdin, err := cmd.StdinPipe(); if err != nil { fmt.Println(err); os.Exit(1); }
        stdout, err := cmd.StdoutPipe(); if err != nil { fmt.Println(err); os.Exit(1); }
        stderr, err := cmd.StderrPipe(); if err != nil { fmt.Println(err); os.Exit(1); }
        defer stdin.Close()
        if err := cmd.Start(); err != nil { fmt.Println(err); os.Exit(1); }
        go func() {
                scr := bufio.NewScanner(stdout)
                for {
                        if scr.Scan() {
                                fmt.Println(scr.Text())
                        }
                        if err := scr.Err(); err != nil {
                                fmt.Println(err)
                                return
                        }
                }
        }()
        go func() {
                scr := bufio.NewScanner(stderr)
                for scr.Scan() {
                        fmt.Println("Err:", scr.Text())
                }
        }()
        if err := cmd.Wait(); err != nil {
                fmt.Println(err)
        }
}

yvs2014 avatar Sep 29 '22 13:09 yvs2014

I have tried it and it's Ok! But what I don't understand is, why should you care about the stdin pipe?

billcoding avatar Sep 30 '22 05:09 billcoding

I don't know and I don't care enough to try figure it out.

Usually some library that is linked (but maybe not used at the moment) that expects something (anything!) to be connected.

Or an "open" that usually gives file descriptor 4 or 5 that now suddenly gives file descriptor 0 and the error check is that the fd must be > 0...

rewolff avatar Sep 30 '22 07:09 rewolff

On Thu, Sep 29, 2022 at 06:05:37AM -0700, yvs2014 wrote:

@rewolff not totally, I suppose /dev/null stdin is already present in that go code it can be emulated with mtr -p -c 10 www.qq.com </dev/null

Yeah! That's the easier mod that us? non-GO people could write to get the same effect. My hypothesis is that go would not connect /dev/null, but simply not open the fd. That fd is then free and can be reassigned to the first open. And a read of returns error instead of EOF. Ahh! Much likelier scenario: open , get fd = 0, and now reads of stdin do NOT get EOF...

rewolff avatar Sep 30 '22 11:09 rewolff

@billcoding

why should you care about the stdin pipe?

mtr is an interactive program, it tests stdin for input, for example if you press 'q' mtr quits, and so on. Non-interactive modes: -r or -w options, and maybe a couple more. Mtr with "-p" works in the interactive mode.

yvs2014 avatar Sep 30 '22 11:09 yvs2014

@rewolf I didn't get that far, it's for golang pandits, easier to open stdin and forget about it

yvs2014 avatar Sep 30 '22 11:09 yvs2014

On Fri, Sep 30, 2022 at 04:39:13AM -0700, yvs2014 wrote:

@rewolf I didn't get that far, it's for golang pandits, easier to open stdin and forget about it

But figuring out what the failure mode is helps us avoid the problem in the future.

rewolff avatar Sep 30 '22 11:09 rewolff

@rewolff if something is wrong with stdin, there are two options for split mode as far as I can see:

  1. print an error and exit
  2. automatically switch to non-interactive mode

the second one works like

% mtr -p localhost </dev/null
split_open(): tcgetattr(): Inappropriate ioctl for device
non-interactive mode is ON
 1	127.0.0.1	0.0	1	1	0.1	0.1	0.1
 1	127.0.0.1	0.0	1	1	0.1	0.1	0.1
 1	127.0.0.1	0.0	1	1	0.1	0.1	0.1
 1	127.0.0.1	0.0	1	1	0.1	0.1	0.1
 1	127.0.0.1	0.0	1	1	0.1	0.1	0.1
 1	127.0.0.1	0.0	2	2	0.1	0.1	0.1
^C

https://github.com/yvs2014/mtr/commit/ed8a8e60dce467283655fce32c29313fc3390cd0

yvs2014 avatar Sep 30 '22 13:09 yvs2014

@yvs2014 i think you meant @rewolff 👍

rewolf avatar Sep 30 '22 13:09 rewolf

Sorry, my typo, fixed

yvs2014 avatar Sep 30 '22 13:09 yvs2014