关闭从TCP连接读取的goroutine而不关闭连接 [英] Close the goroutine reading from a TCP connection without closing connection

查看:99
本文介绍了关闭从TCP连接读取的goroutine而不关闭连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我喜欢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.Readotherwise 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆