Pharaoh
Pharaoh

Reputation: 752

using io.Pipes() for sending and receiving message

I am using os.Pipes() in my program, but for some reason it gives a bad file descriptor error each time i try to write or read data from it.

Is there some thing I am doing wrong?

Below is the code

package main

import (
    "fmt"
    "os"
)

func main() {

    writer, reader, err := os.Pipe()
    if err != nil {
        fmt.Println(err)
    }


    _,err= writer.Write([]byte("hello"))


    if err != nil {
        fmt.Println(err)
    }
    var data []byte

    _, err = reader.Read(data)


    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(string(data))
}

output : write |0: Invalid argument read |1: Invalid argument

Upvotes: 0

Views: 2860

Answers (1)

JimB
JimB

Reputation: 109338

You are using an os.Pipe, which returns a pair of FIFO connected files from the os. This is different than an io.Pipe which is implemented in Go.

The invalid argument errors are because you are reading and writing to the wrong files. The signature of os.Pipe is

func Pipe() (r *File, w *File, err error)

which shows that the returns values are in the order "reader, writer, error".

and io.Pipe:

func Pipe() (*PipeReader, *PipeWriter)

Also returning in the order "reader, writer"

When you check the error from the os.Pipe function, you are only printing the value. If there was an error, the files are invalid. You need to return or exit on that error.

Pipes are also blocking (though an os.Pipe has a small, hard coded buffer), so you need to read and write asynchronously. If you swapped this for an io.Pipe it would deadlock immediately. Dispatch the Read method inside a goroutine and wait for it to complete.

Finally, you are reading into a nil slice, which will read nothing. You need to allocate space to read into, and you need to record the number of bytes read to know how much of the buffer is used.

A more correct version of your example would look like:

reader, writer, err := os.Pipe()
if err != nil {
    log.Fatal(err)
}

var wg sync.WaitGroup
wg.Add(1)
go func() {
    defer wg.Done()
    data := make([]byte, 1024)

    n, err = reader.Read(data)
    if n > 0 {
        fmt.Println(string(data[:n]))
    }

    if err != nil && err != io.EOF {
        fmt.Println(err)
    }
}()

_, err = writer.Write([]byte("hello"))
if err != nil {
    fmt.Println(err)
}

wg.Wait()

Upvotes: 6

Related Questions