package main import ( "io" "log" "net" ) func EchoServer(addr string, done chan struct{}) net.Listener { listener, err := net.Listen("tcp", addr) if err != nil { log.Fatalf("Error listening, %v ", err) } // This implementation does not block, but instead runs it's // accept -> handle loop inside a goroutine go func() { for { select { // When the 'done' channel gets closed or receives // the echo server's listener gets shut down case <-done: listener.Close() return default: conn, err := listener.Accept() if err != nil { log.Printf("Error during accept, %v ", err) return } // Do all the work inside a goroutine so we can quickly accept // other connections go handle(conn) } } }() return listener } func handle(client net.Conn) { var err error for err == nil { // ...simply return everything the client sends to itself _, err = io.Copy(client, client) if err != nil && err != io.EOF { log.Printf("Error during echo %v", err) } } }