管道(pipe)是一种半双工的(或者说是单向的)通讯方式,它只能被用于父进程和子进程以及同祖先的子进程之间的通讯。
使用管道需注意以下四种情况:
- 如果所有指向管道写端的文件描述符都关闭了,仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样。
- 如果有指向管道写端的文件描述符没关闭,持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。
- 如果所有指向管道读端的文件描述符都关闭了,这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。
- 如果有指向管道读端的文件描述符没关闭,持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次write会阻塞,直到管道中有空位置了才写入数据并返回。
匿名管道
原理类似ps aux | grep java
package main
import (
"bytes"
"fmt"
"os/exec"
)
func Ma() {
cmd1 := exec.Command("ps", "aux")
cmd2 := exec.Command("grep", "apipe")
//cmd对象的底层,Stdout与Stdin属性也是通过指向一个字节流实现读写的,这里用新建的字节流代替
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 { //wait会阻塞cmd直到其运行完毕
fmt.Printf("Error: Couldn't wait for the first command: %s\n", err)
return
}
//cmd1的输出与cmd2的输入指向同一个字节流地址
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
}
}
命名管道
原理类似mkfifo -m 777 myfifo cat src.log > myfifo
操作 | 作用 | 特性 |
---|---|---|
reader, writer, err := os.Pipe() |
创建独立管道 | 可以被多路复用,不提供原子操作支持 |
package main
import (
"fmt"
"os"
"time"
)
func Ma() {
reader, writer, err := os.Pipe()
if err != nil {
fmt.Printf("Error: Couldn't create the named pipe: %s\n", err)
}
//Read与Write会在另一端还未就绪时对进程进行阻塞,所以二者需要并发运行
go func() {
output := make([]byte, 100)
n, err := reader.Read(output) //会阻塞,等待writer写入
if err != nil {
fmt.Printf("Error: Couldn't read data from the named pipe: %s\n", err)
}
fmt.Printf("读到了 %d byte(s). [file-based pipe]\n", n)
}()
input := make([]byte, 26)
for i := 65; i <= 90; i++ {
input[i-65] = byte(i)
}
n, err := writer.Write(input) //往管道中写入数据
if err != nil {
fmt.Printf("Error: Couldn't write data to the named pipe: %s\n", err)
}
fmt.Printf("写入了 %d byte(s). [file-based pipe]\n", n)
time.Sleep(1 * time.Hour)
}
操作 | 作用 | 特性 |
---|---|---|
reader, writer := io.Pipe() |
创建内存独立管道 | 基于内存的提供原子操作保证的管道 |
package main
import (
"fmt"
"io"
"time"
)
func Ma() {
reader, writer := io.Pipe()
go func() {
output := make([]byte, 100)
n, err := reader.Read(output)
if err != nil {
fmt.Printf("Error: Couldn't read data from the named pipe: %s\n", err)
}
fmt.Printf("读到了 %d byte(s). [内存中的管道]\n", n)
}()
input := make([]byte, 26)
for i := 65; i <= 90; i++ {
input[i-65] = byte(i)
}
n, err := writer.Write(input)
if err != nil {
fmt.Printf("Error: Couldn't write data to the named pipe: %s\n", err)
}
fmt.Printf("写入了 %d byte(s). [内存中的管道]\n", n)
time.Sleep(200 * time.Millisecond)
}
标签:nil,err,fmt,Printf,Pipe,管道,Error
From: https://www.cnblogs.com/hexug/p/16891716.html