GOLANG探测HTTP连接断开
考虑基于HTTP的RPC,或者HTTP服务器主动通知客户端的机制,就是HTTP Long-Polling,意思就是客户端发起一个长连接,服务器阻塞忍住不响应直到:
这样客户端和服务器之间RPC的效率就非常高,只有在有事件时才会通知。但是,实际上还有一种情况需要处理:
问题就来了,如何在HTTP Handler中探测客户端断开?例如: var incoming chan []byte
http.HandleFunc("/polling",func(w http.ResponseWriter,r *http.Request) {
select { case b := <- incoming: w.Write(b) case <-time.After(5 * time.Second): w.Write("keepalive") // how to detect TCP disconnect event? } })
可能有以下方式:
r.Body Read这种方式是不靠谱的,假设没有Body内容,直接读取检测是否有error: nn,err := io.Copy(ioutil.Discard,r.Body)
实际上返回的是 如果读取完Body后再读呢?收到的是 Peek TcpConn使用reflect获取底层的TCPConn对象,是知道 // A response represents the server side of an HTTP response.
type response struct {
conn *conn
它有个Field就是 这样做的风险就是,不同的GOLANG版本,可能会对底层实现进行变更,在升级时会有风险。 Reflect方式始终不是最好的。 另外,还有一种方式,就是用http hijack方式,这种方式虽然是http库提供的接口,但是很多地方注释都说hijack需要特殊处理,因此也不是最好的方式。参考When to use hijack。 Close Notifier在GO1.1提供了 var incoming chan []byte
http.HandleFunc("/polling",func(w http.ResponseWriter,r *http.Request) {
select {
case <- w.(http.CloseNotifier).CloseNotify():
fmt.Println("connection closed")
}
})
实际上,超时机制始终是需要的,加上之前的逻辑,考虑 func polling(ctx context.Context,incoming chan []byte) {
http.HandleFunc("/polling",func(w http.ResponseWriter,r *http.Request) {
select {
case <- ctx.Done():
fmt.Println("system quit")
case b := <- incoming:
w.Write(b)
case <-time.After(5 * time.Second):
w.Write("keepalive")
case <- w.(http.CloseNotifier).CloseNotify():
fmt.Println("connection closed")
}
})
} (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |