golang 有名管道通信 总结分析

1 golang通过named pipes实现IPC通信

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会阻塞到另一端也打开(通过其他进程或线程)


 

你可能感兴趣的:(java/python/go,golang)