sockets - 关闭从 TCP 连接读取的 goroutine 而不关闭连接
问题描述
我喜欢 Go 在内部处理 I/O 多路复用的方式,epoll
以及另一种机制并自行安排绿色线程(此处为 go-routine),从而可以自由地编写同步代码。
我知道 TCP 套接字non-blocking
会read
在EAGAIN
没有数据可用时提供。鉴于此,conn.Read(buffer)
将检测到这一点并阻止执行连接读取的 go 例程,而套接字缓冲区中没有可用的数据。有没有办法在不关闭底层连接的情况下停止这种 goroutine。我正在使用连接池,因此关闭 TCP 连接对我来说没有意义,并且希望将该连接返回到池中。
这是模拟这种情况的代码:
func main() {
conn, _ := net.Dial("tcp", "127.0.0.1:9090")
// Spawning a go routine
go func(conn net.Conn) {
var message bytes.Buffer
for {
k := make([]byte, 255) // buffer
m, err := conn.Read(k) // blocks here
if err != nil {
if err != io.EOF {
fmt.Println("Read error : ", err)
} else {
fmt.Println("End of the file")
}
break // terminate loop if error
}
// converting bytes to string for printing
if m > 0 {
for _, b := range k {
message.WriteByte(b)
}
fmt.Println(message.String())
}
}
}(conn)
// prevent main from exiting
select {}
}
如果不可能,我可以采取哪些其他方法:
syscall.Read
1)手动调用和处理。在这种情况下,我需要一种方法在调用之前检查套接字是否可读syscall.Read
,否则我最终会浪费不必要的 CPU 周期。对于我的场景,我认为我可以跳过基于事件的轮询事情并继续调用syscall.Read
,因为我的用例中总是有数据。
2)任何建议:)
解决方案
func receive(conn net.TCPConn, kill <-chan struct{}) error {
// Spawn a goroutine to read from the connection.
data := make(chan []byte)
readErr := make(chan error)
go func() {
for {
b := make([]byte, 255)
_, err := conn.Read(b)
if err != nil {
readErr <- err
break
}
data <- b
}
}()
for {
select {
case b := <-data:
// Do something with `b`.
case err := <-readErr:
// Handle the error.
return err
case <-kill:
// Received kill signal, returning without closing the connection.
return nil
}
}
}
从另一个 goroutine发送一个空结构体以kill
停止从连接接收。这是一个在一秒钟后停止接收的程序:
kill := make(chan struct{})
go func() {
if err := receive(conn, kill); err != nil {
log.Fatal(err)
}
}()
time.Sleep(time.Second)
kill <- struct{}{}
这可能不是您正在寻找的内容,因为Read
即使您发送到kill
. 但是,处理传入读取的 goroutine 将终止。
推荐阅读
- html - 从下拉列表中获取值而无需单击按钮
- python - 有没有办法在 Neo4j 或 NetworkX 中找到图形的中心?
- reactjs - 如何在反应中直接从主分支导入库?
- javascript - 已弃用的 Webpack 的 i18n 插件和加载器的替代品
- django - 使用 Django 的 CSRF 攻击
- c# - dataGridView_CellClick 事件
- airflow - Cloud Composer pricing
- javascript - 变异对象:'(
- laravel - BadMethodCallException 调用未定义的方法 App\AskQuestion::email()
- django - 从 Django 中的多个模型中获取数据