traviscross / mtr

Official repository for mtr, a network diagnostic tool
http://www.bitwizard.nl/mtr/
GNU General Public License v2.0
2.64k stars 337 forks source link

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

Open billcoding opened 1 year ago

billcoding commented 1 year ago

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();
        }
    }
}
yvs2014 commented 1 year ago

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)

billcoding commented 1 year ago

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

rewolff commented 1 year ago

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

yvs2014 commented 1 year ago

@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 commented 1 year ago

@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)
        }
}
billcoding commented 1 year ago

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

rewolff commented 1 year ago

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 commented 1 year ago

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...

yvs2014 commented 1 year ago

@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 commented 1 year ago

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

rewolff commented 1 year ago

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.

yvs2014 commented 1 year ago

@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

rewolf commented 1 year ago

@yvs2014 i think you meant @rewolff 👍

yvs2014 commented 1 year ago

Sorry, my typo, fixed