golang并发编程-01多进程编程-02管道

@

1 概述

概念:是一种半双工的(或者说单向的)通讯方式。它只能被用于父进程与子进程以及同祖先的子进程之间的通讯。
优点:简单
缺点:只能单向通讯以及对通讯双方关系上的严格限制

2 cmd的管道

2.1 示例1 (利用管道输出命令结果)

package hello

import (
	"bytes"
	"fmt"
	"io"
	"os/exec"
)

func Hello() {
    //创建一个命令行
	cmd0 := exec.Command("PowerShell.exe","echo","-n","liuBei guanYu zhangFei")
	//创建一个能够获取此命令的输出的管道
	stdout0, err := cmd0.StdoutPipe()
	if err != nil{
		return
	}
	//start方法启动执行命令
	if err := cmd0.Start(); err != nil {
		fmt.Printf("Error: The command No.0 can not be startup: %s\n", err)
		return
	}
	//定义一个缓存区
	var outputBuf0 bytes.Buffer
	for {
	    //定义一个二进制切片tempOutput 来接收管道stdout0的数据
		tempOutput := make([]byte, 5)
		n, err := stdout0.Read(tempOutput)
		if err != nil {
		    //如果收到错误是结尾就跳出循环。
			if err == io.EOF {
				break
			} else {
				fmt.Printf("Error: Can not read data from the pipe: %s\n", err)
				return
			}
		}
		//如果管道中有数据,则写入缓存(outputBuf0)
		if n > 0 {
			outputBuf0.Write(tempOutput[:n])
		}
	}
    //从缓存中读数
	fmt.Printf("%s\n", outputBuf0.String())
}

2.2 示例2(两条命令间的交互)

package hello

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os/exec"
)
func Apipe02(){
	cmd1 := exec.Command("PowerShell.exe","ls")
	cmd2 := exec.Command("PowerShell.exe","findstr.exe", "hello")

	//在cmd1代表的命令之上建立一个输出管道
	stdout1, err := cmd1.StdoutPipe()
	if err != nil {
		fmt.Printf("Error: Can not obtain the stdout pipe for command: %s\n", err)
		return
	}
	if err := cmd1.Start(); err != nil {
		fmt.Printf("Error: The command can not be startup: %s\n", err)
		return
	}

	//创建一个来自cmd1输出管道(stdout1)的输入管道outputBuf1
	outputBuf1 := bufio.NewReader(stdout1)

	//建立cmd2的输出管道
	stdin2,err := cmd2.StdinPipe()
	if err != nil {
		fmt.Printf("Error: Can not obtain the stdin pipe for command: %s\n", err)
		return
	}
	//cmd1输出管道(stdout1)的输入管道(outputBuf1)连接到cmd2的输出管道
	_,err = outputBuf1.WriteTo(stdin2)

	//定义一个缓存
	var outputBuf2 bytes.Buffer
	//将cmd2的标准输出指向缓存
	cmd2.Stdout = &outputBuf2
	//执行cmd2
	if err := cmd2.Start(); err != nil {
		fmt.Printf("Error: The command can not be startup: %s\n", err)
		return
	}
	//关闭cmd2的输出管道
	err = stdin2.Close()
	if err != nil {
		fmt.Printf("Error: Can not close the stdio pipe: %s\n", err)
		return
	}

	//等待cmd2 写完再去读
	if err := cmd2.Wait(); err != nil {
		fmt.Printf("Error: Can not wait for the command: %s\n", err)
		return
	}
	//读缓存
	fmt.Printf("%s\n", outputBuf2.String())
}

3. 内存管道

  • 创建管道
reader, writer := io.Pipe()
  • 写入
 n,_err := writer.Write([]byte("hello"))

返回值n 是输入的字节数

  • 读取

创建一个切片以接收数据

	buffer := make([]byte, 100)
	n,err = reader.Read(buffer)
  • 示例
	reader, writer := io.Pipe()
	// 创建携程给writer
	go func() {
		_,err = writer.Write([]byte("hello"))
		if err != nil{
			return
		}
		defer writer.Close()
	}()

	buffer := make([]byte, 100)
	_,err = reader.Read(buffer)
	if err != nil {
		return err
	}
	fmt.Println(string(buffer))
	return nil

4. os管道

reader, writer, err := os.Pipe()

和内存管道用法相同


posted on 2022-05-04 14:20  运维开发玄德公  阅读(23)  评论(0编辑  收藏  举报  来源

导航