@Konvergent
начинающий разработчик

Как работать с внешним процессом из GO?

Привет!
Ещё одна моя попытка спросить, как реализовать такую штуку:
Go-прога запускает внешний процесс через exec.Command, назовём его воркер.
Воркер это простой эхо-сервер, получает на stdin строку и возвращает её обратно.
Как не плодя и не перезапуская процесс-воркер (т.е. запустили и он постоянно в памяти крутится), постоянно (в цикле) писать ему на stdin и читать из stdout/err. Т.е. реализовать работу с ним в режиме строка-запроса, и ответ ввиде эха этой строки в качестве ответа?
Куча материала про каналы, го-рутины и запуск процессов, но подобного примера я не нашёл. Помогите пожалуйста.
  • Вопрос задан
  • 509 просмотров
Решения вопроса 1
@Konvergent Автор вопроса
начинающий разработчик
В итоге, у меня заработало так:
package main

import (
    "io"
    "fmt"
    "log"
    "bufio"
    "os/exec"    
    "strconv"
)

func get_err(id string, stderr io.ReadCloser, errs chan<- string) {	
	defer stderr.Close()

	rd_err := bufio.NewReader(stderr)

	for {    	
    	err_line, _, err := rd_err.ReadLine()
    	if err != nil {
    		if err == io.EOF {    		
    			fmt.Println("Exit by EOF...")
      		}

      		fmt.Println("Error reading stdout:", err)
      		return      		
    	}

    	errs <- id+" - "+string(err_line)
  	}
}

func worker(id int, tasks <-chan string, status chan string, errors chan string) {

	// выставляем настройки запуска воркера
	cmd := exec.Command("perl", "./worker.pl")

    stdin, err := cmd.StdinPipe()
    if err != nil {
        log.Panic(err)
    }

    stdout, err := cmd.StdoutPipe()
    if err != nil {
        log.Panic(err)
    }

    stderr, err := cmd.StderrPipe()
    if err != nil {
        log.Panic(err)
    }

    go get_err(strconv.Itoa(id),stderr, errors)
    
    err = cmd.Start()
    if err != nil {
        log.Panic(err)
    }	

    rd := bufio.NewReader(stdout)
    
	for {		
		t := <- tasks
		task_id := t[0]
		task := t[1:len(t)]
		stdin.Write([]byte(task))

		fmt.Println("STDIN " + strconv.Itoa(id) + " >>> " + " - task " + string(task_id) + " " + task)
		
		line, _, err := rd.ReadLine()
    	if err != nil {
    		if err == io.EOF {    		
    			fmt.Println("Exit by EOF...")
      		}

      		fmt.Println("Error reading stdout:", err)
      		return      		
    	}

    	status <- strconv.Itoa(id)+" - task "+string(task_id)+" "+string(line)+"\n"
	}

	err = cmd.Wait()
    if err != nil {
        log.Panic(err)
    }
}

func main() {

	test_words := []string{`raz`, `dva`, `tri`,} 

	tasks 	:= make(chan string)
	status 	:= make(chan string)
	errors 	:= make(chan string)

	go func(){
		for {
			bad := <- errors
			fmt.Println("<<< STDERR ", bad)
		}			
	}()

	go func(){
		for {			
			req := <- status
			fmt.Println("<<< STDOUT ", req)
		}
	}()

	// запуск воркера
	go worker(w, tasks, status, errors)
	
	// приём/передача запросов/ответов
	for i := 0; i < len(test_words); i++ {
		tasks <- strconv.Itoa(i)+test_words[i]+"\n"
	} 
}
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы