使用管道与程序进程通信

时间:2013-02-09 13:40:59

标签: go ipc pipe

我希望能够在从Golang程序中生成它们之后与某些程序进行完全通信。我已经拥有的是产生过程并根据从stdout读取的最后一行通过管道进行交谈:

package main

import (
    "fmt"
    "io"
    "log"
    "os/exec"
    "strings"
)

var stdinPipe io.WriteCloser
var stdoutPipe io.ReadCloser
var err error

func main() {
    cmd := &exec.Cmd{
        Path: "/Users/seba/Projects/go/src/bootstrap/in",
        Args: []string{"program"},
    }

    stdinPipe, err = cmd.StdinPipe()

    if err != nil {
        log.Fatal(err)
    }

    stdoutPipe, err = cmd.StdoutPipe()

    if err != nil {
        log.Fatal(err)
    }

    err = cmd.Start()

    if err != nil {
        log.Fatal(err)
    }

    var stdoutLines []string
    go stdoutManage(stdoutLines, stdoutController)

    cmd.Wait()
}

// TODO: imporove as in io.Copy
func stdoutManage(lines []string, manager func(string)) {
    buf := make([]byte, 32*1024)

    for {
        nr, err := stdoutPipe.Read(buf)

        if nr > 0 {
            thelines := strings.Split(string(buf), "\n")
            for _, l := range thelines {
                manager(l)
                lines = append(lines, l)
            }
        }

        buf = make([]byte, 32*1024) // clear buf

        if err != nil {
            break
        }
    }
}

然而,这种方法存在程序清除终端输出和程序的问题,这些程序以某种方式缓冲它的标准输入或根本不使用标准输入(不知道是否可能)。

所以问题是:是否有一种可移植的方式与程序交谈(它可以是非Golang解决方案)?

1 个答案:

答案 0 :(得分:3)

这样的问题通常与C library which changes its default buffering模式有关,具体取决于stdin / stdout / stderr究竟是什么。

如果stdout是终端,则缓冲自动设置为行缓冲,否则设置为缓冲。

这与您相关,因为当您通过管道运行程序时,它们没有连接到终端,因此会有缓冲,这会影响这种用途。

要修复,您需要使用假tty作为终端,但就像管道一样。这是一个实现the pty interface的库,我实际上没有尝试过,但它看起来是正确的!