看着net.TCPListener。考虑到Go并发模式,人们会期望将这个系统功能作为一个通道来实现,这样您就可以从一个chan *net.Conn函数中得到一个Listen(),或者类似的东西。
但它似乎是接受()的方式,而这只是块,就像系统接受。只是它残废了,因为:
所以我要做的事情是:
acceptChannel = make(chan *Connection)
go func() {
for {
rw, err := listener.Accept()
if err != nil { ... handle error ... close(acceptChannel) ... return }
s.acceptChannel <-&Connection{tcpConn: rw, .... }
}
}()这样,我就可以在select中使用多个服务器套接字,或者与其他通道一起使用对Accept()的等待。我是不是遗漏了什么?我是新来的,所以我可能忽略了一些事情--但真的没有用自己的并发模式实现自己的阻塞系统功能吗?我真的需要为我想要听的每一个插座(可能是几百或数千个)建立一个单独的大猩猩吗?这是正确的成语使用,还是有更好的方法?
发布于 2015-04-29 16:02:09
你的代码很好。您甚至可以更进一步地替换:
s.acceptChannel <-&Connection{tcpConn: rw, .... }通过以下方式:
go handleConnection(&Connection{tcpConn: rw, .... })正如注释中提到的,例程不是系统线程,它们是由Go运行时管理的轻量级线程。当您为每个连接创建一个例程时,您可以很容易地使用阻塞操作,这些操作更容易实现。Go运行时然后为您选择例程,所以您要寻找的行为只是在其他地方,隐藏在语言中。你看不见,但到处都是。
现在,如果您需要一些更复杂的东西,并且根据我们的对话,实现类似于select的超时,那么您将完全按照您的建议:将所有新连接推送到一个通道,并使用一个计时器对其进行多路复用。这似乎是进去的路。
请注意,如果你们中的一个接受者失败了,你不能关闭接收通道,因为另一个接受者在写信给它时会感到恐慌。
我的(更全面的)例子:
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
}
}https://stackoverflow.com/questions/29948497
复制相似问题