All the Listeners from the bind folder should have the option of being created with SO_REUSEPORT
, so a Config
should look like:
// Config is the configuration for Bind()
type Config struct {
.......
Port uint16
// PortStrict tells us not to try other ports
PortStrict bool
// PortAttempts indicates how many times we will try finding a port
PortAttempts int
// Defaultport indicates the port to try on the first attempt if Port is zero
DefaultPort uint16
// PortReuse indicates that the listener is able to reuse the port between threads/processes
PortReuse bool
.....
// ListenTCP is the helper to use to listen on TCP ports
ListenTCP func(network string, laddr *net.TCPAddr) (*net.TCPListener, error)
// ListenUDP is the helper to use to listen on UDP ports
ListenUDP func(network string, laddr *net.UDPAddr) (*net.UDPConn, error)
.......
}
also default ListenTCP
and ListenUDP
should be created
var listenConfig = net.ListenConfig{
Control: Control,
}
func ListenTCP(network, address string) (net.Listener, error) {
return listenConfig.Listen(context.Background(), "tcp", address)
}
func ListenUDP(network, address string) (net.PacketConn, error) {
return listenConfig.ListenPacket(context.Background(), "udp", address)
}
with Control
function implemented for windows, linux, unix
example for unix:
import (
"syscall"
"golang.org/x/sys/unix"
)
func Control(network, address string, c syscall.RawConn) (err error) {
controlErr := c.Control(func(fd uintptr) {
err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
if err != nil {
return
}
err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
})
if controlErr != nil {
err = controlErr
}
return
}