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  }