From 8b39d6cc8221e1e3758d93d1fa30ca7837822445 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 7 Jul 2025 21:23:01 -0400 Subject: [PATCH] Teensy TCP echo server --- tcp-challenge/server/cmd/server/main.go | 89 +++++++++++++++++++++++++ tcp-challenge/server/go.mod | 3 + 2 files changed, 92 insertions(+) create mode 100644 tcp-challenge/server/cmd/server/main.go create mode 100644 tcp-challenge/server/go.mod diff --git a/tcp-challenge/server/cmd/server/main.go b/tcp-challenge/server/cmd/server/main.go new file mode 100644 index 0000000..723f5d1 --- /dev/null +++ b/tcp-challenge/server/cmd/server/main.go @@ -0,0 +1,89 @@ +package main + +import ( + "context" + "io" + "log" + "net" + "os" + "os/signal" + "strconv" + "syscall" +) + +func main() { + ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) + defer stop() + + addr := ":7765" + if len(os.Args) > 1 { + addr = os.Args[1] + } + + poolSize := 10 + if len(os.Args) > 2 { + if v, err := strconv.ParseInt(os.Args[2], 10, 64); err != nil { + log.Fatal(err) + } else { + poolSize = int(v) + } + } + + log.Printf("listening at %v (workers=%v)", addr, poolSize) + + listener, err := net.Listen("tcp", addr) + if err != nil { + log.Fatal(err) + } + + workers := []*worker{} + requests := make(chan net.Conn) + + for i := 0; i < poolSize; i++ { + w := &worker{id: i, r: requests} + go w.Start(ctx) + workers = append(workers, w) + } + + for { + select { + case <-ctx.Done(): + return + default: + log.Println("accepting connection") + conn, err := listener.Accept() + if err != nil { + log.Printf("failed to accept connection: %v", err) + continue + } + + log.Println("accepted connection") + requests <- conn + } + } +} + +type worker struct { + id int + r chan net.Conn +} + +func (w *worker) Start(ctx context.Context) { + log.Printf("[worker %v] starting loop", w.id) + + for { + select { + case <-ctx.Done(): + log.Printf("[worker %v] exiting", w.id) + return + case conn := <-w.r: + log.Printf("[worker %v] handling connection", w.id) + + io.Copy(conn, conn) + + if err := conn.Close(); err != nil { + log.Printf("[worker %v] failed to echo: %v", w.id, err) + } + } + } +} diff --git a/tcp-challenge/server/go.mod b/tcp-challenge/server/go.mod new file mode 100644 index 0000000..512d12f --- /dev/null +++ b/tcp-challenge/server/go.mod @@ -0,0 +1,3 @@ +module git.meatballhat.com/x/box-o-sand/tcp-challenge/server + +go 1.21.4