关闭从TCP连接读取的goroutine而不关闭连接 [英] Close the goroutine reading from a TCP connection without closing connection
问题描述
我喜欢Go在内部处理I / O复用的方式,其中 epoll
和另一种机制可以自己调度绿色线程(此处为例行程序),从而可以自由编写同步代码。
I love the way Go handles I/O multiplexing internally which epoll
and another mechanisms and schedules green threads (go-routine here) on its own giving the freedom to write synchronous code.
我知道TCP套接字是无阻塞
和 read
将在没有可用数据时给出 EAGAIN
。鉴于此, conn.Read(buffer)
将检测到此情况,并阻止go例程进行连接读取,而套接字缓冲区中没有可用数据。有没有一种方法可以在不关闭基础连接的情况下停止此类go例程。我正在使用连接池,因此关闭TCP连接对我来说没有意义,并且想要将该连接返回到该池。
I know TCP sockets are non-blocking
and read
will give EAGAIN
when no data is available. Given that, conn.Read(buffer)
will detect this and blocks the go routine doing a connection read with no data available in the socket buffer. Is there a way to stop such go routine without closing the underlying connection. I am using a connection pool so closing the TCP connection won't make sense for me and want to return that connection back to the pool.
下面是模拟代码此类情况:
Here is the code to simulate such scenario:
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 {}
}
如果不可能的话,我还能采取哪些其他方法:
What are the other approaches can I take if it's not possible:
1 )调用 syscall.Read
并手动处理。在这种情况下,我需要一种方法在调用 syscall之前检查套接字是否可读。否则,我将浪费不必要的CPU周期。对于我的情况,我认为我可以跳过基于事件的轮询,而继续调用
syscall.Read
,因为用例中始终有数据。
1) Call syscall.Read
and handle this manually. In this case, I need a way to check if the socket is readable before calling syscall.Read
otherwise I will end up wasting unnecessary CPU cycles. For my scenario, I think I can skip the event based polling thing and keep on calling syscall.Read
as there always be data in my use case.
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
发送一个空结构以停止从连接中接收。这是一个会在一秒钟后停止接收的程序:
Send an empty struct to kill
from another goroutine to stop receiving from the connection. Here's a program that stops receiving after a second:
kill := make(chan struct{})
go func() {
if err := receive(conn, kill); err != nil {
log.Fatal(err)
}
}()
time.Sleep(time.Second)
kill <- struct{}{}
这可能与您要找的不完全相同,因为阅读goroutine仍然是即使发送给 kill
,也无法在读取
上被阻止。但是,处理传入读取的goroutine将终止。
This might not be exactly what you're looking for, because the reading goroutine would still be blocked on Read
even after you send to kill
. However, the goroutine that handles incoming reads would terminate.
这篇关于关闭从TCP连接读取的goroutine而不关闭连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!