package reuseportimport ()type dialer struct {// All address that are _not_ loopback or unspecified (0.0.0.0 or ::). specific []*net.TCPAddr// All loopback addresses (127.*.*.*, ::1). loopback []*net.TCPAddr// Unspecified addresses (0.0.0.0, ::) unspecified []*net.TCPAddr}func ( *dialer) (, string) (net.Conn, error) {return .DialContext(context.Background(), , )}func randAddr( []*net.TCPAddr) *net.TCPAddr {iflen() > 0 {return [rand.Intn(len())] }returnnil}// DialContext dials a target addr.//// In-order://// 1. If we're _explicitly_ listening on the preferred source address for the destination address// (per the system's routes), we'll use that listener's port as the source port.// 2. If we're listening on one or more _unspecified_ addresses (zero address), we'll pick a source// port from one of these listener's.// 3. Otherwise, we'll let the system pick the source port.func ( *dialer) ( context.Context, , string) (net.Conn, error) {// We only check this case if the user is listening on a specific address (loopback or // otherwise). Generally, users will listen on the "unspecified" address (0.0.0.0 or ::) and // we can skip this section. // // This lets us avoid resolving the address twice, in most cases.iflen(.specific) > 0 || len(.loopback) > 0 { , := net.ResolveTCPAddr(, )if != nil {returnnil, } := .IPif !.IsLoopback() && !.IsGlobalUnicast() {returnnil, fmt.Errorf("undialable IP: %s", ) }// If we're listening on some specific address and that specific address happens to // be the preferred source address for the target destination address, we try to // dial with that address/port. // // We skip this check if we _aren't_ listening on any specific addresses, because // checking routing tables can be expensive and users rarely listen on specific IP // addresses.iflen(.specific) > 0 {if , := netroute.New(); == nil {if , , , := .Route(); == nil {for , := range .specific {if .IP.Equal() {returnreuseDial(, , , ) } } } } }// Otherwise, if we are listening on a loopback address and the destination is also // a loopback address, use the port from our loopback listener.iflen(.loopback) > 0 && .IsLoopback() {returnreuseDial(, randAddr(.loopback), , ) } }// If we're listening on any uspecified addresses, use a randomly chosen port from one of // these listeners.iflen(.unspecified) > 0 {returnreuseDial(, randAddr(.unspecified), , ) }// Finally, just pick a random port.varnet.Dialerreturn .DialContext(, , )}func newDialer( map[*listener]struct{}) *dialer { := make([]*net.TCPAddr, 0) := make([]*net.TCPAddr, 0) := make([]*net.TCPAddr, 0)for := range { := .Addr().(*net.TCPAddr)if .IP.IsLoopback() { = append(, ) } elseif .IP.IsUnspecified() { = append(, ) } else { = append(, ) } }return &dialer{specific: ,loopback: ,unspecified: , }}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.