TCP accept and Go 并发模型

标签 tcp concurrency go

查看 net.TCPListener。考虑到 Go 的并发范式,人们会期望这个系统功能作为一个 channel 来实现,这样你就可以从 Listen() 中得到一个 chan *net.Conn函数,或类似的东西。

但似乎 Accept() 是方法,它只是阻塞,就像系统接受一样。除了残废,因为:

  • 没有合适的 select() 可以与它​​一起使用,因为 go 更喜欢 channel
  • 无法为服务器套接字设置阻塞选项。

所以我正在做类似的事情:

    acceptChannel = make(chan *Connection)
    go func() {
      for {
       rw, err := listener.Accept()
       if err != nil { ... handle error ... close(acceptChannel) ... return }
       s.acceptChannel <-&Connection{tcpConn: rw, .... }
      }
    }()

这样我就可以在一个选择中使用多个服务器套接字,或者将 Accept() 上的等待与其他 channel 多路复用。我错过了什么吗?我是 Go 的新手,所以我可能会忽略一些事情——但是 Go 真的没有用自己的并发范例实现自己的阻塞系统功能吗?我真的需要为我想听的每个套接字(可能成百上千个)单独的 goroutine 吗?这是正确的用法,还是有更好的方法?

最佳答案

您的代码很好。您甚至可以更进一步替换:

s.acceptChannel <-&Connection{tcpConn: rw, .... }

与:

go handleConnection(&Connection{tcpConn: rw, .... })

如评论中所述,例程不是系统线程,它们是由 Go runtime 管理的轻量级线程。当您为每个连接创建一个例程时,您可以轻松地使用更容易实现的阻塞操作。 Go 运行时然后为您选择 例程,因此您正在寻找的行为只是在其他地方,埋在语言中。你看不到它,但它无处不在。

现在,如果您需要更复杂的东西,并且根据我们的谈话,实现类似于带超时选择的东西,您将完全按照您的建议进行操作:将所有新连接推送到一个 channel 并使用计时器对其进行多路复用.这似乎是 Go 中的方法。

请注意,如果你们中的一个接受器失败,您不能关闭接受 channel ,因为另一个接受器在写入时会 panic 。

我的(更完整的)示例:

newConns := make(chan net.Conn)

// For every listener spawn the following routine
go func(l net.Listener) {
    for {
        c, err := l.Accept()
        if err != nil {
            // handle error (and then for example indicate acceptor is down)
            newConns <- nil
            return
        }
        newConns <- c
    }
}(listener)

for {
    select {
    case c := <-newConns:
        // new connection or nil if acceptor is down, in which case we should
        // do something (respawn, stop when everyone is down or just explode)
    case <-time.After(time.Minute):
        // timeout branch, no connection for a minute
    }
}

关于TCP accept and Go 并发模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29948497/

相关文章:

java - 有没有办法像在 ExecutorCompletionService 中那样在 spring 中轮询一组 Future 对象?

hadoop - 使用 Zookeeper 的分布式应用程序

multithreading - 是否有一个 API 可以让 N 个线程(或 N 个线程上的 N 个闭包)完成?

gorm 使用 find 返回空

http - 终止或中止 HTTP 请求

powershell - 如何在 Powershell 中自动检查 Telnet 端口?`

java - ObjectInputStream 无法识别我的对象数据格式

json - 在 go websocket 服务器上获取 json 数据

http - 将套接字与进程相关联

java - 在断开连接的套接字上写入不会抛出