使用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
对于一个没有长度的缓冲区,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
参考资料:
问题在于你创建了一个长度为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错误,因为它没有空间写入任何数据。

