有一个tcp服务器。我需要从 syscall.RawConn 获取数据。我正在尝试这样做:
for {
for _, conn := range tcpConns {
rawConn, err := conn.SyscallConn()
if err != nil {
fmt.Printf("get raw conn error: %s\n", err)
}
rawConn.Read(readConn)
}
}
func readConn(fd uintptr) bool {
f := os.NewFile(fd, "file")
b, err := ioutil.ReadAll(f)
if err != nil {
fmt.Printf("read file error: %s\n", err)
return false
} else {
fmt.Printf("New data: %s\n", string(b))
return true
}
}
执行时,在终端中我观察到:
read file error: read file: resource temporarily unavailable
那些。返回此错误ioutil.ReadAll(f)。此外,该函数readConn返回 false 并且程序执行被阻止。那些。rawConn.Read(readConn)即使我的函数已执行并返回结果,代码也不会继续。文档说,在 readConn 返回 false 的情况下,将在可能时再尝试读取数据。但是什么都没有发生,也不清楚“何时成为可能”是什么意思。
我已经尝试在函数中返回 true,readConn但随后在该行的无限循环的第二个循环上执行块ioutil.ReadAll(f)。我应该怎么做才能获取数据?
我知道你不能syscall.RawConn从 net.TCPConn 接收和读取,但我不喜欢你需要为那里的每个连接创建一个 goroutine 并且它会占用大量内存,所以我想创建 1 个无限循环来读取来自没有 goroutines 的所有连接的数据
Go 以非阻塞方式创建套接字。如果没有数据,则系统调用
read返回一个错误EAGAIN,Go 提供一个测试消息resource temporarily unavailable如果忽略此错误,则它
rawConn可以工作。注:如果你使用
RawConn.Read,那么你不需要调用ReadAll--RawConn.Read块,这意味着它会调用你的函数readConn,直到函数返回true。用法示例
RawConn.Read。该程序使用系统调用从套接字文件描述符中读取syscall.Read。测试运行
echo "Test" | nc -N -w 1 -v localhost 54321服务器程序输出:更新
异步套接字读取器。此选项不会阻止
RawConn.Read.示例 - 客户端发送一行,然后等待一秒钟并发送另一行:
服务器:
省略号中隐藏了 9 万个(!)异步读取器调用。
主要缺点是此选项会 100% 加载 CPU,因为它会不断拉动套接字。
对于没有冗余请求的多个套接字的真正异步处理,您需要
syscall.Select使用syscall.EpollWait