golang基于named pipes实现进程间的IPC通信
可以单独使用go write()或 go read()方法
write()是非阻塞的,read()是阻塞的。
package main
import (
"fmt"
"log"
"os"
"time"
"bufio"
"syscall"
)
var pipeFile = "/tmp/pipe.ipc"
func main() {
os.Remove(pipeFile)
err := syscall.Mkfifo(pipeFile, 0666)
if err != nil {
log.Fatal("create named pipe error:", err)
}
go write()
go read()
for {
time.Sleep(time.Second * 1000)
}
}
func read(){
fmt.Println("open a named pipe file for read.")
file, _ := os.OpenFile(pipeFile, os.O_RDWR, os.ModeNamedPipe)
reader := bufio.NewReader(file)
for {
line, err := reader.ReadBytes('\n')
fmt.Println("read...")
if err == nil {
fmt.Print("load string: " + string(line))
}
}
}
func write() {
fmt.Println("start schedule writing.")
f, err := os.OpenFile(pipeFile, os.O_RDWR, 0777)
if err != nil {
log.Fatalf("error opening file: %v", err)
}
i := 0
for {
fmt.Println("write string to named pipe file.")
f.WriteString(fmt.Sprintf("test write times:%d\n", i))
i++
time.Sleep(time.Second)
if i == 10{
break
}
}
}
Method:
package main
import (
"bufio"
"fmt"
"log"
"os"
"syscall"
"time"
)
var pipeFile = "pipe.log"
func main() {
os.Remove(pipeFile)
err := syscall.Mkfifo(pipeFile, 0666)
if err != nil {
log.Fatal("Make named pipe file error:", err)
}
go scheduleWrite()
fmt.Println("open a named pipe file for read.")
file, err := os.OpenFile(pipeFile, os.O_CREATE, os.ModeNamedPipe)
if err != nil {
log.Fatal("Open named pipe file error:", err)
}
reader := bufio.NewReader(file)
for {
line, err := reader.ReadBytes('\n')
if err == nil {
fmt.Print("load string:" + string(line))
}
}
}
func scheduleWrite() {
fmt.Println("start schedule writing.")
f, err := os.OpenFile(pipeFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0777)
if err != nil {
log.Fatalf("error opening file: %v", err)
}
i := 0
for {
fmt.Println("write string to named pipe file.")
f.WriteString(fmt.Sprintf("test write times:%d\n", i))
i++
time.Sleep(time.Second)
}
}
/* Test result */
/*================================
go run pipe.go
open a named pipe file for read.
start schedule writing.
write string to named pipe file.
load string:test write times:0
write string to named pipe file.
load string:test write times:1
write string to named pipe file.
load string:test write times:2
=================================*/
有名管道,mkfifo了两个文件,然后文件io-open打开的时候,阻塞在open里面了。一般情况下(没有指定O_NONBLOCK),只读open要阻塞到某个其他进程为写而打开这个FIFO为止。类似的,只写open要阻塞到其他进程为读而打开它为止。
正确:p1 create p1 ,open p1 with read
p2 open p2 with write
if p1 not open p1 with read p2 will block.
如果指定了O_NONBLOCK,则只读open立即返回,但是如果没有进程为读而打开一个FIFO,那么只写open将返回-1,并将errno设置成ENXIO
注意打开模式:
1,open模式,由O_RDONLY/O_WRONLY改成O_RDWR
2,假如文件1 O_RDONLY管道,文件2 O_WRONLY管道
总之:
关于有名管道open时阻塞的问题
1. 发现错误
在学习Unix网络编程卷二的有名管道FIFO时,无意间犯下一个错误,故写此总结。
在写FIFO的服务器和客户端之间通信的代码时,服务器端主函数创建两个有名管道,然后分被以读写打开两个管道:
readfd = open(FIFO1, O_RDONLY, 0);
writefd = open(FIFO2, O_WRONLY, 0);
1
2
3
然而在写客户端主函数代码时,打开管道的顺序写反,如下:
readfd = open(FIFO2, O_RDONLY, 0);
writefd = open(FIFO1, O_WRONLY, 0);
//应该将两行代码顺序颠倒
于是乎,服务器和客户端无法正常通信。
2. 及时总结
当open一个FIFO时,非阻塞标志(O_NONBLOCK)会产生下列影响:
一般情况下(没有指定O_NONBLOCK),只读open要阻塞到某个其他进程为写而打开这个FIFO为止。类似的,只写open要阻塞到某个其他进程为读而打开它为止。
如果指定了O_NONBLOCK,则只读open立即返回,但是如果没有进程为读而打开一个FIFO,那么只写open将返回-1,并将errno设置成ENXIO。
查看man page man 2 open也可以看到
Opening the read or write end of a FIFO blocks until the other end is also opened (by another process or thread). See fifo(7) for further details.
1
大意为:以读或写打开一个FIFO会阻塞到另一端也打开(通过其他进程或线程)