package main
import (
"context"
"crypto/tls"
"flag"
"fmt"
"net"
"time"
"golang.org/x/net/http2"
)
type Stats struct {
conn net.Conn
BytesRead int64
BytesWritten int64
}
func (t *Stats) Read(b []byte) (n int, err error) {
n, err = t.conn.Read(b)
t.BytesRead += int64(n)
return
}
func (t *Stats) Write(b []byte) (n int, err error) {
n, err = t.conn.Write(b)
t.BytesWritten += int64(n)
return
}
func (t *Stats) Close() error {
return t.conn.Close()
}
func (t *Stats) LocalAddr() net.Addr {
return t.conn.LocalAddr()
}
func (t *Stats) RemoteAddr() net.Addr {
return t.conn.RemoteAddr()
}
func (t *Stats) SetDeadline(time time.Time) error {
return t.conn.SetDeadline(time)
}
func (t *Stats) SetReadDeadline(time time.Time) error {
return t.conn.SetReadDeadline(time)
}
func (t *Stats) SetWriteDeadline(time time.Time) error {
return t.conn.SetWriteDeadline(time)
}
func NewStatsConn(conn net.Conn) *Stats {
return &Stats{
conn: conn,
}
}
func main() {
resolve := flag.String("resolve", "1.1.1.1", "")
server := flag.String("server", "cloudflare.com", "ServerName is used to verify the hostname on the returned certificates unless InsecureSkipVerify is given. It is also included in the client's handshake to support virtual hosting unless it is an IP address.")
port := flag.Uint("port", 443, "")
flag.Parse()
var address string
if *resolve == "" {
address = fmt.Sprintf("%s:%d", *server, *port)
} else {
address = fmt.Sprintf("%s:%d", *resolve, *port)
}
tcpConn, err := net.Dial("tcp", address)
if err != nil {
panic(err)
}
defer tcpConn.Close()
statsConn := NewStatsConn(tcpConn)
tlsConn := tls.Client(statsConn, &tls.Config{
ServerName: *server,
NextProtos: []string{"h2"},
})
tr := http2.Transport{}
http2Conn, err := tr.NewClientConn(tlsConn)
if err != nil {
panic(err)
}
defer http2Conn.Close()
for http2Conn.State().MaxConcurrentStreams == 0 {
time.Sleep(time.Millisecond * 100)
}
fmt.Println("init", statsConn.BytesRead, statsConn.BytesWritten)
r, w := statsConn.BytesRead, statsConn.BytesWritten
for i := 0; i < 3; i++ {
start := time.Now()
err = http2Conn.Ping(context.Background())
rtt := time.Since(start)
fmt.Println(*server, "index", i,
"read", statsConn.BytesRead-r, "written", statsConn.BytesWritten-w,
"rtt(ms)", uint(rtt.Milliseconds()))
r, w = statsConn.BytesRead, statsConn.BytesWritten
if err != nil {
panic(err)
}
time.Sleep(time.Second)
}
}