Quantcast
Channel: プログラミング
Viewing all articles
Browse latest Browse all 7991

Goメモ-451 (mkfifoメモ)(5)(write-nonblocking) - いろいろ備忘録日記

$
0
0

関連記事

Goメモ-447 (mkfifoメモ)(1)(create) - いろいろ備忘録日記

Goメモ-448 (mkfifoメモ)(2)(read) - いろいろ備忘録日記

Goメモ-449 (mkfifoメモ)(3)(write) - いろいろ備忘録日記

Goメモ-450 (mkfifoメモ)(4)(read-nonblocking) - いろいろ備忘録日記

GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ

概要

以下、自分用のメモです。忘れないうちにメモメモ。。。

Go側から名前付きパイプ(mkfifo)を扱うことがあったので、忘れない内にメモしておこうと思いました。

今回は名前付きパイプファイルからの書き込み(ノンブロッキングモード)について。

なお、標準ライブラリにある syscallパッケージの Mkfifo()でも行えるのですが

サンプルでは sys/unixの方を使っています。

サンプル

//go:build linuxpackage main

import (
    "bufio""errors""flag""fmt""log""os""sync""syscall""time""golang.org/x/sys/unix"
)

var (
    fname string
)

func init() {
    log.SetFlags(log.Lmicroseconds)

    flag.StringVar(&fname, "fname", "", "FIFO file name")
    flag.Parse()
}

func main() {
    if err := run(); err != nil {
        log.Fatal(err)
    }
}

func run() error {
    //// 名前付きパイプをノンブロッキングモードで開く//   明示的なノンブロッキングモードの指定は os.OpenFile() では行えないため//   golang.org/x/sys/unix を利用する//var (
        fd  int
        f   *os.File
        err error
    )

    log.Println("[Before] unix.Open(unix.O_WRONLY|unix.O_NONBLOCK)")

    // 名前付きパイプを書込みでノンブロッキングモードで開く場合に O_WRONLY を指定すると// 読み込み側が開かれていない場合 `ENXIO(no such device or address)` が発生する。//// 逆に読み込みでノンブロッキングモードで開く場合はここではエラーとならず// 実際に読み込む際に書込みが行われていない場合に即EOFが返ることになる。// ノンブロッキングリードする処理は ../read-nonbloking/ を参照のこと。//// 読み込みと書込みでエラーが発生する箇所が異なる点に注意。//// REFERENCES//   - https://qiita.com/seriru13/items/39ed2431dfd959ad512efor {
        fd, err = unix.Open(fname, unix.O_WRONLY|unix.O_NONBLOCK, 0666)
        if err != nil {
            var sysErr syscall.Errno
            if errors.As(err, &sysErr) && sysErr == unix.ENXIO {
                log.Printf("[ENXIO] %s", sysErr)
                <-time.After(200 * time.Millisecond)
                continue
            }

            return err
        }

        break
    }

    f = os.NewFile(uintptr(fd), fname)
    if f == nil {
        return fmt.Errorf("invalid file descriptor")
    }
    defer f.Close() // ここで f.Close() しているので、上で unix.Close(fd) は不要

    log.Println("[After ] unix.Open(unix.O_WRONLY|unix.O_NONBLOCK)")

    //// データを書き込み//type (
        data struct {
            numWrites int
            err       error
        }
    )
    var (
        writer  = bufio.NewWriter(f)
        results = make(chan data)
        timeout = 1500 * time.Millisecond
        done    = make(chanstruct{})
        wg      sync.WaitGroup
    )

    wg.Add(1)
    gofunc() {
        defer wg.Done()

        n, err := writer.WriteString("helloworld\n")
        if err == nil {
            err = writer.Flush()
        }

        results <- data{n, err}
    }()

    select {
    case r := <-results:
        if r.err != nil {
            return r.err
        }

        log.Printf("Write %d byte(s)", r.numWrites)
    case<-time.After(timeout):
        log.Println("timeout")
    }

    close(done)
    wg.Wait()

    returnnil
}

実行すると以下のようになります。

$ task
task: [build] go build -o app .
task: [create-fifo]rm-f ./tmp-fifo
task: [create-fifo] mkfifo ./tmp-fifo -m0666
task: [run] ./app -fname ./tmp-fifo &
task: [run]sleep1
05:32:05.279144[Before] unix.Open(unix.O_WRONLY|unix.O_NONBLOCK)
05:32:05.279327[ENXIO] no such device or address
05:32:05.479725[ENXIO] no such device or address
05:32:05.680111[ENXIO] no such device or address
05:32:05.880493[ENXIO] no such device or address
05:32:06.080974[ENXIO] no such device or address
task: [run]cat ./tmp-fifo
05:32:06.281373[ENXIO] no such device or address
05:32:06.483128[After ] unix.Open(unix.O_WRONLY|unix.O_NONBLOCK)
05:32:06.483383 Write 11 byte(s)
helloworld

ノンブロッキングモードの場合、読み取りと書き込みでエラー判定を行う場所が異なることに注意が必要ですね。

参考情報

6.3 Named Pipes (FIFOs - First In First Out)

Ubuntu Manpage: mkfifo, mkfifoat - FIFOスペシャルファイル(名前付きパイプ)を作成する

Master the Linux ‘mkfifo’ Command: A Comprehensive Guide | by Peter Hou | Medium

Goのおすすめ書籍


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。


Viewing all articles
Browse latest Browse all 7991

Trending Articles