【发布时间】:2013-09-16 09:59:19
【问题描述】:
我最近在玩 go 并尝试创建一些服务器来响应 tcp 连接上的客户端。
我的问题是我如何干净地关闭服务器并中断当前在以下调用中“阻塞”的 go-routine
func (*TCPListener) 接受?
Accept 在 Listener 接口中实现 Accept 方法;它等待下一次调用并返回一个通用的 Conn。
这些错误也很少被记录。
【问题讨论】:
标签: go
我最近在玩 go 并尝试创建一些服务器来响应 tcp 连接上的客户端。
我的问题是我如何干净地关闭服务器并中断当前在以下调用中“阻塞”的 go-routine
func (*TCPListener) 接受?
Accept 在 Listener 接口中实现 Accept 方法;它等待下一次调用并返回一个通用的 Conn。
这些错误也很少被记录。
【问题讨论】:
标签: go
这就是我想要的。也许将来会帮助某人。 注意使用 select 和 "c" 通道将它与退出通道结合起来
ln, err := net.Listen("tcp", ":8080")
if err != nil {
// handle error
}
defer ln.Close()
for {
type accepted struct {
conn net.Conn
err error
}
c := make(chan accepted, 1)
go func() {
conn, err := ln.Accept()
c <- accepted{conn, err}
}()
select {
case a := <-c:
if a.err != nil {
// handle error
continue
}
go handleConnection(a.conn)
case e := <-ev:
// handle event
return
}
}
【讨论】:
c 会被耗尽。如果由于循环终止而变满,则剩余的发送将永远不会完成。
您不一定需要额外的 go 例程(不断接受),只需指定 Deadline。
for 示例:
for {
// Check if someone wants to interrupt accepting
select {
case <- someoneWantsToEndMe:
return // runs into "defer listener.Close()"
default: // nothing to do
}
// Accept with Deadline
listener.SetDeadline(time.Now().Add(1 * time.Second)
conn, err := listener.Accept()
if err != nil {
// TODO: Could do some err checking (to be sure it is a timeout), but for brevity
continue
}
go handleConnection(conn)
}
【讨论】:
只需 Close() 和从 net.Listen(...) 调用中获得的 net.Listener 并从正在执行的 goroutine 返回。
【讨论】:
net.OpError 或 net 包中定义的其他错误类型。 _, ok := err.(net.OpError) 将使 ok 成为 true 或 false 取决于 err 实际上是否属于 net.OpError 类型