当读卡器断开连接时,命名管道(FIFO)数据在哪里?

问题描述 投票:1回答:1

假设我有一个producer.goconsumer.goconsumer.go从UNIX命名管道读取,生产者写入命名管道。

正如预期的那样,如果您只启动生产者或消费者程序之一,它会挂起,因为管道的另一侧没有读取器或写入器。

现在,如果我启动两个程序,然后立即从消费者CTRL-C,生产者继续向管道发送数据,据我所知,这些数据的大小没有限制(我发送了80MB)

如果我再次启动消费者程序(当生产者仍然在运行时),它会开始从命名管道中提取数据,而不是在消费者程序未运行时我“错过”的数据。

我的问题是:当命名管道的读取器断开连接时,发送到命名管道的数据会发生什么?

这是我的consumer.goproducer.go计划:

consumer.go

package main

import (
    "io"
    "io/ioutil"
    "log"
    "os"
    "syscall"
)

func main() {
    syscall.Mkfifo("fifo0", 0777)
    fp, err := os.OpenFile("fifo0", os.O_RDONLY, 0777)
    if err != nil {
        log.Fatalf("Could not open fifo0: %s", err)
    }
    tee := io.TeeReader(fp, os.Stdout)
    ioutil.ReadAll(tee)
}

producer.go

package main

import (
    "fmt"
    "io"
    "log"
    "os"
    "strings"
    "time"
)

func main() {
    dots := strings.Repeat(".", 990)
    fifo, err := os.OpenFile("fifo0", os.O_WRONLY, 0777)
    if err != nil {
        log.Fatalf("Could not open fifo0: %s", err)
    }
    defer fifo.Close()
    w := io.MultiWriter(os.Stdout, fifo)
    for i := 0; i < 8000; i++ {
        fmt.Fprintf(w, "%010d%s\n", i, dots)
        time.Sleep(time.Millisecond * 10)
    }
}
unix go fifo mkfifo
1个回答
0
投票

FIFO需要至少一个源和一个目标才能将数据传输到任何地方。一个读者独自等待从某人那里拉出来,而一个作家独自等待发送给某人。通过这种方式,一对一管道中没有间隙。

因此,如果您仍在尝试从断开连接或不存在的管道的一端读取或写入,那么答案是数据无处可去;管道被“阻塞”并且不能保存自己的数据。所以这取决于你的代码如何处理这种情况。

producer.go中,即使不再有连接,循环也会继续运行。因为FprintfMultiWriter不会出于任何原因引发代码停止错误。在这种情况下,您可以在循环中添加一个检查,或者为fifo对象的断开连接添加一个事件处理程序。

似乎存在消失数据差距的原因是因为循环继续迭代i并生成它无法发送的字符串。

© www.soinside.com 2019 - 2024. All rights reserved.