func (s *EchoServer) Stop() error {
	err := s.tcpListener.Close()
	if err != nil {
		return err
	}
	err = s.udpListener.Close()
	if err != nil {
		return err
	}
	return nil
}
Stop stops s gracefully and closes its listener.
package netserver
import (
	"crypto/tls"
	"fmt"
	"io"
	"net"
	"github.com/caddyserver/caddy"
	"github.com/caddyserver/caddy/caddytls"
)
type EchoServer struct {
	LocalTCPAddr string
	tcpListener  net.Listener
	udpListener  net.PacketConn
	udpSemaphore chan int
	config       *Config
}
func NewEchoServer(l string, c *Config) (*EchoServer, error) {
	return &EchoServer{
		LocalTCPAddr: l,
		udpSemaphore: make(chan int, 100),
		config:       c,
	}, nil
}
func (s *EchoServer) Listen() (net.Listener, error) {
	var listener net.Listener
	tlsConfig, err := caddytls.MakeTLSConfig([]*caddytls.Config{s.config.TLS})
	if err != nil {
		return nil, err
	}
	inner, err := net.Listen("tcp", fmt.Sprintf("%s", s.LocalTCPAddr))
	if err != nil {
		return nil, err
	}
	if tlsConfig != nil {
		listener = tls.NewListener(inner, tlsConfig)
	} else {
		listener = inner
	}
	return listener, nil
}
func (s *EchoServer) ListenPacket() (net.PacketConn, error) {
	return net.ListenPacket("udp", fmt.Sprintf("%s", s.LocalTCPAddr))
}
func (s *EchoServer) Serve(ln net.Listener) error {
	s.tcpListener = ln
	for {
		conn, err := ln.Accept()
		if err != nil {
			return err
		}
		go func(c net.Conn) {
			_, err := io.Copy(c, c)
			if err != nil {
				fmt.Printf("io.Copy error: %v\n", err)
			}
			c.Close()
		}(conn)
	}
}
func (s *EchoServer) ServePacket(con net.PacketConn) error {
	s.udpListener = con
	for {
		s.udpSemaphore <- 1  
		go s.echoUDP(con)
	}
}
func (s *EchoServer) echoUDP(con net.PacketConn) {
	defer func() { <-s.udpSemaphore }()
	buf := make([]byte, 4096)
	nr, addr, err := con.ReadFrom(buf)
	if err != nil {
		s.udpListener.Close()
	}
	_, err = con.WriteTo(buf[:nr], addr)
	if err != nil {
		s.udpListener.Close()
	}
}