Skip to content

Instantly share code, notes, and snippets.

@spraints
Last active April 30, 2025 12:28
Show Gist options
  • Save spraints/42b3ec473655ce665f8c215bf6dcfe5e to your computer and use it in GitHub Desktop.
Save spraints/42b3ec473655ce665f8c215bf6dcfe5e to your computer and use it in GitHub Desktop.
play with go http and sockets
module gist.github.com/spraints/42b3ec473655ce665f8c215bf6dcfe5e
go 1.22.2
require (
github.com/vishvananda/netlink v1.3.0 // indirect
github.com/vishvananda/netns v0.0.4 // indirect
golang.org/x/sys v0.10.0 // indirect
)
github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk=
github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs=
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
package main
import (
"context"
"log"
)
func measureLink(ctx context.Context) {
log.Println("measureLink: disabled on darwin")
}
package main
import (
"context"
"fmt"
"log"
"syscall"
"time"
"github.com/vishvananda/netlink"
)
func measureLink(ctx context.Context) {
ticker := time.NewTicker(time.Second / 5)
defer ticker.Stop()
for {
select {
case <-ticker.C:
// yay!
case <-ctx.Done():
log.Println("measureLink: done")
return
}
socks, err := netlink.SocketDiagTCP(syscall.AF_INET)
if err != nil {
log.Printf("measureLink: error getting sock diag: %v", err)
return
}
for _, sock := range socks {
saddr := fmt.Sprintf("%v:%v", sock.ID.Source, sock.ID.SourcePort)
daddr := fmt.Sprintf("%v:%v", sock.ID.Destination, sock.ID.DestinationPort)
log.Printf("%v -> %v", saddr, daddr)
return
}
}
}
package main
import (
"context"
"io"
"log"
"net/http"
"os"
"sync"
"time"
)
const addr = "127.0.0.1:7373"
func main() {
defer log.Println("main: done")
var wg sync.WaitGroup
defer wg.Wait()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
wg.Add(1)
go func() { defer wg.Done(); measureLink(ctx) }()
// Demonstrate that response isn't sent to client until the server's
// handler returns.
log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
srv := &http.Server{
Addr: addr,
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
wg.Add(1)
defer wg.Done()
log.Println("server: request received")
// set CHUNKED=1 this to make the client receive the
// response headers before the sleep finishes.
//
// note the response still won't be completely finished
// until this func returns.
if os.Getenv("CHUNKED") == "1" {
if f, ok := w.(http.Flusher); ok {
f.Flush()
}
}
w.Write([]byte("Hello, world!"))
log.Println("server: response written")
time.Sleep(time.Second)
log.Println("server: response finished")
}),
}
go srv.ListenAndServe()
log.Println("client: sending request")
resp, err := http.Get("http://" + addr + "/")
if err != nil {
log.Println(err)
return
}
log.Printf("client: response received %v", resp.StatusCode)
io.Copy(os.Stdout, resp.Body)
log.Println("client: done!")
time.Sleep(time.Second)
cancel()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment