Golang实现匿名管道

1.管道相关概念

  • 管道是一种半双工(或者说单向)的通信方式,只能用于父进程与子进程以及同祖先的子进程之间的通信。例如,使用shell命令的时候,常常使用到管道,例如:
[root@localhost lianxi]# ps aux | cat -n
  • shell为每个命令都创建一个进程,然后把左边命令都创建一个进程,然后把左边命令的标准输出用管道与右边命令的标准输入连接起来。管道的优点在于简单,而缺点则是只能单向通信以及对通信双方关系上的严格限制。

2.go实现管道

  • 对于管道,go是支持的。通过标准库代码包os/exec中的API,可以在执行操作系统命令并在此之上建立管道。下面创建一个exec.Cmd类型的值
cmd := exec.Command("echo","-n","my first command comes from golang")
  • 在exec.Cmd类型之上有一个名为start的方法,可以使用它启动命令
if err := cmd.Start();err != nil{
   fmt.Printf("error : the command can not be startup %s\n",err)
}
  • 为了创建一个能够获取命令的输出管道,需要在if语句之前加入如下语句:
stdout,err := cmd.StdoutPipe()
if err != nil{
   fmt.Printf("err:couldn't obtain the stdout pipe for command %s\n",err)
} 
  • 变量cmd的StdoutPipe方法会返回一个输出管道,这里把代表这个输出管道的值赋给了变量stdout。stdout的类型是io.ReadCloser,后者是一个扩展了io.Reader接口的接口类型,并定义了可关闭的数据读取行为
    • 有了stdout,启动上述命令之后,就可以通过调用它的read方法来获取命令的输出
output := make([]byte,50)
n,err := stdout.Read(output)
   if err != nil{
   fmt.Printf("err:couldn't read data from the pipe %s\n",err)
   }
fmt.Printf("%s\n",n)

3.匿名管道

  • 管道可以把一个命令的输出作为另一个命令的输入,go代码也可以做到
package main

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

func main()  {
	cmd1 := exec.Command("ps","aux")
	cmd2 := exec.Command("grep","root")
	var outputbuf1 bytes.Buffer
	cmd1.Stdout = &outputbuf1
	if err := cmd1.Start();err!=nil{
		fmt.Printf("error:the first command can not be startup %s\n",err)
		return
	}
	if err := cmd1.Wait();err!=nil{
		fmt.Printf("error:couldn't wait for the first command %s\n",err)
		return
	}
	cmd2.Stdin = &outputbuf1
	var outputbuf2 bytes.Buffer
	cmd2.Stdout = &outputbuf2
	if err := cmd2.Start();err!=nil{
		fmt.Printf("error:the second command can not be startup %s\n",err)
		return
	}
	if err := cmd2.Wait();err!=nil{
		fmt.Printf("error:couldn't wait for the second command %s\n",err)
		return
	}
	fmt.Printf("%s\n",outputbuf2.Bytes())
}
输出:(只截取前面部分)
root               659   3.0  0.1  4513160  18240   ??  Ss   10:16AM   0:01.31 /System/Library/PrivateFrameworks/XprotectFramework.framework/Versions/A/XPCServices/XprotectService.xpc/Contents/MacOS/XprotectService
root             16596   1.9  0.0  4398004   4328   ??  Ss    8:39PM   0:00.02 /Library/Manufacturer/Endpoint Agent/SEHA.app/Contents/MacOS/SEHA
root               230   1.6  0.3  4542564  48776   ??  Ss   10:14AM   0:14.87 /usr/libexec/syspolicyd
root               145   1.6  0.1  4506104  12056   ??  Ss   10:14AM   0:28.81 /System/Library/PrivateFrameworks/TCC.framework/Resources/tccd system
  • *bytes.Buffer类型实现了io.Writer接口,所以才能将&outputbuf1赋给cmd1.stdout。这样,当cmd1启动后的所有输出内容都会被写入到outputbuf1。
  • cmd1的wait方法的调用会一直阻塞,直到cmd1完全运行结束
  • 再设置cmd2的stdin和stdout字段,启动cmd2,并等待运行完毕
  • 由于*bytes.Buffer类型也实现了io.Reader接口,才能把&outputbuf1也赋给cmd2.Stdin。正是因为与outputbuf1有关的这两次赋值,cmd2的输入才能与cmd1的输出串联在一起。这个媒介是outputbuf1,起到了管道的作用
  • 为了获取cmd2的所有输出内容,需要等到它运行结束后再去查看缓冲区outputbuf2中的内容
  • cmd1和cmd2的示例模拟出了操作系统命令 ps aux | grep root
  • 不过,cmd2的输出会与直接运行这个操作系统命令得到的输出有所不同。因为该示例程序相当于在自身运行过程中又运行了上面的这个操作系统命令
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值