main.go
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
package main

import (
	"bufio"
	"bytes"
	"context"
	"fmt"
	"log"
	"net"
	"strings"
	"time"
)

const newline byte = 10

func handleConn(ctx context.Context, c net.Conn) {
	_ = ctx
	defer c.Close()
	r := bufio.NewReaderSize(c, 64*1024)

	for {
		if err := c.SetReadDeadline(time.Now().Add(30 * time.Second)); err != nil {
			return
		}
		line, err := r.ReadBytes(newline)
		if err != nil {
			return
		}

		msg := strings.TrimSpace(string(bytes.TrimSpace(line)))
		if strings.EqualFold(msg, "quit") {
			return
		}

		if err := c.SetWriteDeadline(time.Now().Add(10 * time.Second)); err != nil {
			return
		}
		fmt.Fprintf(c, "OK %d bytes%c", len(msg), newline)
	}
}

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	ln, err := net.Listen("tcp", "127.0.0.1:9090")
	if err != nil {
		log.Fatalf("listen: %v", err)
	}
	defer ln.Close()

	go func() {
		<-ctx.Done()
		ln.Close()
	}()

	log.Printf("tcp server listening on %s", ln.Addr().String())
	for {
		c, err := ln.Accept()
		if err != nil {
			return
		}
		go handleConn(ctx, c)
	}
}

How It Works

Concurrent TCP server implementing a simple line-based protocol with deadlines and graceful shutdown.

Listens on a TCP port, spawns goroutines per client, sets read and write deadlines, reads newline-delimited commands, responds accordingly, and shuts down via context cancellation to close listeners and wait for workers.

Key Concepts

  • 1Deadlines prevent stuck connections from hanging the server.
  • 2WaitGroup and context ensure orderly shutdown.
  • 3Line-based protocol makes parsing simple and predictable.

When to Use This Pattern

  • Prototype for custom text protocols such as chat or command shells.
  • Integration test server for network clients.
  • Educational example of concurrent TCP handling.

Best Practices

  • Sanitize and limit input to prevent abuse.
  • Handle partial reads, writes, and EOF explicitly.
  • Close client connections in defer blocks to avoid leaks.
Go Version1.18+
Difficultyintermediate
Production ReadyYes
Lines of Code65