使用Golang的net.Conn.Read无法从UNIX套接字读取数据

使用Golang的net.Conn.Read无法从UNIX套接字读取数据 我正在尝试使用Go进行简单的UNIX套接字通信。我有一个现有的服务绑定到磁盘上的命名套接字,我希望Go通过这个接口与之交互。为了测试,我使用Netcat创建了这样一个命名套接字:

$ nc -vlU /tmp/sock
Bound on /tmp/sock
Listening on /tmp/sock
...

Go代码只是打开套接字,并在一个限速循环中对其进行写入和读取:

package main

import (
    "net"
    "fmt"
    "time"
)

func main() {
    ctl, err := net.Dial("unix", "/tmp/sock")
    if err != nil {
        fmt.Printf("err: %v\n", err)
        return
    }

    buf := make([]byte, 0, 256)
    for {
        time.Sleep(time.Second)
        ctl.Write([]byte("test write\n"))
        n, err := ctl.Read(buf)
        fmt.Printf("len:%v, data:%v, err:%v\n", n, buf, err)
    }
}

我在Netcat控制台中看到了写入的内容:

$ nc -vlU /tmp/sock
Bound on /tmp/sock
Listening on /tmp/sock
Connection received on /tmp/sock
test write
test write
test write
...

但Go端却在无限循环,同时返回零长度且没有错误。

$ go run test.go
len:0, data:[], err:<nil>
len:0, data:[], err:<nil>
len:0, data:[], err:<nil>
len:0, data:[], err:<nil>
len:0, data:[], err:<nil>
...

所以,写入在Netcat控制台中观察到了,因此是有效的。但读取是怎么回事?因为net.Dial接口允许设置timeout,我原本期望net.Conn.Read操作是一个阻塞操作。

我哪里做错了?


更多关于使用Golang的net.Conn.Read无法从UNIX套接字读取数据的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

对于一个没有长度的缓冲区,buf[:256] 是什么意思?

更多关于使用Golang的net.Conn.Read无法从UNIX套接字读取数据的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


事实证明,当你尝试读取一个零长度缓冲区时,观察到的就是这种行为。也就是说,

buf := make([]byte, 0, N)

对比

buf := make([]byte, N)

我哪里做错了?

你应该这样写:

buf := make([]byte, 0, 256)
for {
	// ...
	n, err := ctl.Read(buf[:cap(buf)])
	buf = buf[:n]
    if err != nil {
        // handle error
    }
    // ...
}

buf[:256]256 <= cap(buf) 时为 buf 设置一个新的长度:

buf = buf[0:256:cap(buf)]


package main

import "fmt"

func main() {
	buf := make([]byte, 0, 256)
	fmt.Println(len(buf), cap(buf))
	buf = buf[:256]
	fmt.Println(len(buf), cap(buf))
}

https://play.golang.org/p/XL6lfrQ92Km

0 256
256 256

参考资料:

Go 博客:Go 切片:用法与内部原理

Go 编程语言规范:切片表达式

问题在于你创建了一个长度为0的字节切片。make([]byte, 0, 256)创建了一个长度为0、容量为256的切片,Read方法无法向长度为0的切片中写入数据。

修改为:

package main

import (
    "net"
    "fmt"
    "time"
)

func main() {
    ctl, err := net.Dial("unix", "/tmp/sock")
    if err != nil {
        fmt.Printf("err: %v\n", err)
        return
    }

    buf := make([]byte, 256)  // 修改这里:创建长度为256的切片
    for {
        time.Sleep(time.Second)
        ctl.Write([]byte("test write\n"))
        n, err := ctl.Read(buf)
        fmt.Printf("len:%v, data:%v, err:%v\n", n, buf[:n], err)  // 只打印实际读取的部分
    }
}

或者使用带长度的切片初始化:

buf := make([]byte, 256)

Read方法需要足够长度的切片来存储读取的数据。当切片长度为0时,Read会立即返回0和nil错误,因为它没有空间写入任何数据。

回到顶部