Golang中http服务器在处理hijacked连接时Io.copy挂起问题
Golang中http服务器在处理hijacked连接时Io.copy挂起问题 由于被劫持的连接没有上下文,很难预测连接是否已关闭。我添加了一个计数器来测量由io.copy持有的连接数量,结果显示即使客户端断开连接且超时触发后,部分连接仍会长时间保持。
package main
import (
"context"
"fmt"
"github.com/gadelkareem/go-helpers"
"io"
"net"
"net/http"
"sync"
"sync/atomic"
"time"
)
const Timeout = 5 * time.Second
var counter int64
func main() {
go func() {
for range time.Tick(Timeout) {
fmt.Printf("%d requests being processed\n", atomic.LoadInt64(&counter))
}
}()
s := &http.Server{
Addr: ":8888",
Handler: http.HandlerFunc(Serve),
}
s.ListenAndServe()
}
func Serve(w http.ResponseWriter, r *http.Request) {
atomic.AddInt64(&counter, 1)
if r.Method == http.MethodConnect {
// HTTPS
hij, ok := w.(http.Hijacker)
if !ok {
return
}
hj, bufrw, err := hij.Hijack()
h.PanicOnError(err)
bufrw.WriteString("HTTP/1.0 200 OK\r\n\r\n")
bufrw.Flush()
target, err := net.DialTimeout("tcp", r.URL.Host, Timeout)
h.PanicOnError(err)
// Not sure if this is needed since we add a context timeout
// Just leaving it for the example
dl := time.Now().Add(Timeout)
err = hj.SetDeadline(dl)
h.PanicOnError(err)
err = target.SetDeadline(dl)
h.PanicOnError(err)
var wg sync.WaitGroup
ctx, cancel := context.WithTimeout(r.Context(), Timeout)
defer cancel()
go func() {
for {
select {
case <-ctx.Done():
hj.Close()
target.Close()
println("context canceled")
return
}
}
}()
targetTCP, _ := target.(*net.TCPConn)
hjTCP, _ := hj.(*net.TCPConn)
wg.Add(2)
go copyAndClose(targetTCP, hjTCP, &wg)
go copyAndClose(hjTCP, targetTCP, &wg)
wg.Wait()
} else {
//ignore HTTP for this example
}
atomic.AddInt64(&counter, -1)
return
}
func copyAndClose(dst, src *net.TCPConn, wg *sync.WaitGroup) {
io.Copy(dst, src)
dst.CloseWrite()
src.CloseRead()
wg.Done()
}
你可以在此处复现代码:https://gist.github.com/gadelkareem/3484fe05747f9fcc55b408cf23e92484
这段代码是否存在问题,或者这可能是一个潜在的bug?
更多关于Golang中http服务器在处理hijacked连接时Io.copy挂起问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于Golang中http服务器在处理hijacked连接时Io.copy挂起问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
没关系,那是计数器递减前不可劫持连接的返回值

