Skip to content

Instantly share code, notes, and snippets.

@HattieWebb
Last active November 30, 2022 16:01
Show Gist options
  • Save HattieWebb/2000c514b37a6a0bb5e8b55fadbe3433 to your computer and use it in GitHub Desktop.
Save HattieWebb/2000c514b37a6a0bb5e8b55fadbe3433 to your computer and use it in GitHub Desktop.
get open connection num from a *http.Transport
package main
import (
"sync"
"net/http"
"time"
"io/ioutil"
"fmt"
"net"
"context"
)
func main(){
// here is the test code. copy/paste/use NewTransportWithConnectNum.
handler:=http.HandlerFunc(func(w http.ResponseWriter, req *http.Request){
time.Sleep(time.Second)
_,_ = w.Write([]byte("success"))
})
go func(){
_ = http.ListenAndServe("127.0.0.1:10098",handler)
}()
tran:= NewTransportWithConnectNum(&http.Transport{})
client:=&http.Client{
Transport:tran,
}
wg:=sync.WaitGroup{}
for i:=0;i<10;i++{
wg.Add(1)
go func(){
resp,err:=client.Get("http://127.0.0.1:10098")
if err!=nil{
panic(err)
}
_,_ = ioutil.ReadAll(resp.Body)
_ = resp.Body.Close()
wg.Done()
}()
}
wg.Wait()
fmt.Println(tran.GetConnectionNum())
}
// you can wrap a *http.Transport to get open connection number.
// do not support if DialTLS is set.
func NewTransportWithConnectNum(old *http.Transport) *Transport{
connectCounter:=&connectCounter_t{}
tran:=&Transport{
Transport: old,
connectCounter: connectCounter,
}
oldDialer:=tran.getOldDialer()
tran.Transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error){
conn1,err:=oldDialer(ctx,network,addr)
if err!=nil{
return nil,err
}
connectCounter.add(1)
conn2:=&connWithCounter{
Conn: conn1,
connectCounter: connectCounter,
}
return conn2,nil
}
return tran
}
type Transport struct{
*http.Transport
connectCounter *connectCounter_t
}
func (tran *Transport) GetConnectionNum() int{
return tran.connectCounter.get()
}
var zeroDialer net.Dialer
func (tran *Transport) getOldDialer() func(ctx context.Context, network, addr string) (net.Conn, error){
if tran.DialContext!=nil{
return tran.DialContext
}
if tran.Dial!=nil{
return func(ctx context.Context, network, addr string) (net.Conn, error){
return tran.Dial(network,addr)
}
}
return zeroDialer.DialContext
}
type connectCounter_t struct{
connectNum int
connectNumLocker sync.Mutex
}
func (c *connectCounter_t) add(num int){
c.connectNumLocker.Lock()
c.connectNum+=num
c.connectNumLocker.Unlock()
}
func (c *connectCounter_t) get()(num int){
c.connectNumLocker.Lock()
num = c.connectNum
c.connectNumLocker.Unlock()
return num
}
type connWithCounter struct{
net.Conn
closeCounterSyncOnce sync.Once
connectCounter *connectCounter_t
}
func (conn *connWithCounter) Close() (err error){
err = conn.Conn.Close()
conn.closeCounterSyncOnce.Do(func(){
conn.connectCounter.add(-1)
})
return err
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment