github.com/nsqio/nsq@v1.3.0/internal/protocol/tcp_server.go (about) 1 package protocol 2 3 import ( 4 "fmt" 5 "net" 6 "runtime" 7 "strings" 8 "sync" 9 10 "github.com/nsqio/nsq/internal/lg" 11 ) 12 13 type TCPHandler interface { 14 Handle(net.Conn) 15 } 16 17 func TCPServer(listener net.Listener, handler TCPHandler, logf lg.AppLogFunc) error { 18 logf(lg.INFO, "TCP: listening on %s", listener.Addr()) 19 20 var wg sync.WaitGroup 21 22 for { 23 clientConn, err := listener.Accept() 24 if err != nil { 25 // net.Error.Temporary() is deprecated, but is valid for accept 26 // this is a hack to avoid a staticcheck error 27 if te, ok := err.(interface{ Temporary() bool }); ok && te.Temporary() { 28 logf(lg.WARN, "temporary Accept() failure - %s", err) 29 runtime.Gosched() 30 continue 31 } 32 // theres no direct way to detect this error because it is not exposed 33 if !strings.Contains(err.Error(), "use of closed network connection") { 34 return fmt.Errorf("listener.Accept() error - %s", err) 35 } 36 break 37 } 38 39 wg.Add(1) 40 go func() { 41 handler.Handle(clientConn) 42 wg.Done() 43 }() 44 } 45 46 // wait to return until all handler goroutines complete 47 wg.Wait() 48 49 logf(lg.INFO, "TCP: closing %s", listener.Addr()) 50 51 return nil 52 }