Source File
tcpdialer.go
Belonging Package
github.com/valyala/fasthttp
package fasthttp
import (
)
// Dial dials the given TCP addr using tcp4.
//
// This function has the following additional features comparing to net.Dial:
//
// - It reduces load on DNS resolver by caching resolved TCP addressed
// for DNSCacheDuration.
// - It dials all the resolved TCP addresses in round-robin manner until
// connection is established. This may be useful if certain addresses
// are temporarily unreachable.
// - It returns ErrDialTimeout if connection cannot be established during
// DefaultDialTimeout seconds. Use DialTimeout for customizing dial timeout.
//
// This dialer is intended for custom code wrapping before passing
// to Client.Dial or HostClient.Dial.
//
// For instance, per-host counters and/or limits may be implemented
// by such wrappers.
//
// The addr passed to the function must contain port. Example addr values:
//
// - foobar.baz:443
// - foo.bar:80
// - aaa.com:8080
func ( string) (net.Conn, error) {
return defaultDialer.Dial()
}
// DialTimeout dials the given TCP addr using tcp4 using the given timeout.
//
// This function has the following additional features comparing to net.Dial:
//
// - It reduces load on DNS resolver by caching resolved TCP addressed
// for DNSCacheDuration.
// - It dials all the resolved TCP addresses in round-robin manner until
// connection is established. This may be useful if certain addresses
// are temporarily unreachable.
//
// This dialer is intended for custom code wrapping before passing
// to Client.Dial or HostClient.Dial.
//
// For instance, per-host counters and/or limits may be implemented
// by such wrappers.
//
// The addr passed to the function must contain port. Example addr values:
//
// - foobar.baz:443
// - foo.bar:80
// - aaa.com:8080
func ( string, time.Duration) (net.Conn, error) {
return defaultDialer.DialTimeout(, )
}
// DialDualStack dials the given TCP addr using both tcp4 and tcp6.
//
// This function has the following additional features comparing to net.Dial:
//
// - It reduces load on DNS resolver by caching resolved TCP addressed
// for DNSCacheDuration.
// - It dials all the resolved TCP addresses in round-robin manner until
// connection is established. This may be useful if certain addresses
// are temporarily unreachable.
// - It returns ErrDialTimeout if connection cannot be established during
// DefaultDialTimeout seconds. Use DialDualStackTimeout for custom dial
// timeout.
//
// This dialer is intended for custom code wrapping before passing
// to Client.Dial or HostClient.Dial.
//
// For instance, per-host counters and/or limits may be implemented
// by such wrappers.
//
// The addr passed to the function must contain port. Example addr values:
//
// - foobar.baz:443
// - foo.bar:80
// - aaa.com:8080
func ( string) (net.Conn, error) {
return defaultDialer.DialDualStack()
}
// DialDualStackTimeout dials the given TCP addr using both tcp4 and tcp6
// using the given timeout.
//
// This function has the following additional features comparing to net.Dial:
//
// - It reduces load on DNS resolver by caching resolved TCP addressed
// for DNSCacheDuration.
// - It dials all the resolved TCP addresses in round-robin manner until
// connection is established. This may be useful if certain addresses
// are temporarily unreachable.
//
// This dialer is intended for custom code wrapping before passing
// to Client.Dial or HostClient.Dial.
//
// For instance, per-host counters and/or limits may be implemented
// by such wrappers.
//
// The addr passed to the function must contain port. Example addr values:
//
// - foobar.baz:443
// - foo.bar:80
// - aaa.com:8080
func ( string, time.Duration) (net.Conn, error) {
return defaultDialer.DialDualStackTimeout(, )
}
var defaultDialer = &TCPDialer{Concurrency: 1000}
// Resolver represents interface of the tcp resolver.
type Resolver interface {
LookupIPAddr(context.Context, string) (names []net.IPAddr, err error)
}
// TCPDialer contains options to control a group of Dial calls.
type TCPDialer struct {
// Concurrency controls the maximum number of concurrent Dials
// that can be performed using this object.
// Setting this to 0 means unlimited.
//
// WARNING: This can only be changed before the first Dial.
// Changes made after the first Dial will not affect anything.
Concurrency int
// LocalAddr is the local address to use when dialing an
// address.
// If nil, a local address is automatically chosen.
LocalAddr *net.TCPAddr
// This may be used to override DNS resolving policy, like this:
// var dialer = &fasthttp.TCPDialer{
// Resolver: &net.Resolver{
// PreferGo: true,
// StrictErrors: false,
// Dial: func (ctx context.Context, network, address string) (net.Conn, error) {
// d := net.Dialer{}
// return d.DialContext(ctx, "udp", "8.8.8.8:53")
// },
// },
// }
Resolver Resolver
// DNSCacheDuration may be used to override the default DNS cache duration (DefaultDNSCacheDuration)
DNSCacheDuration time.Duration
tcpAddrsMap sync.Map
concurrencyCh chan struct{}
once sync.Once
}
// Dial dials the given TCP addr using tcp4.
//
// This function has the following additional features comparing to net.Dial:
//
// - It reduces load on DNS resolver by caching resolved TCP addressed
// for DNSCacheDuration.
// - It dials all the resolved TCP addresses in round-robin manner until
// connection is established. This may be useful if certain addresses
// are temporarily unreachable.
// - It returns ErrDialTimeout if connection cannot be established during
// DefaultDialTimeout seconds. Use DialTimeout for customizing dial timeout.
//
// This dialer is intended for custom code wrapping before passing
// to Client.Dial or HostClient.Dial.
//
// For instance, per-host counters and/or limits may be implemented
// by such wrappers.
//
// The addr passed to the function must contain port. Example addr values:
//
// - foobar.baz:443
// - foo.bar:80
// - aaa.com:8080
func ( *TCPDialer) ( string) (net.Conn, error) {
return .dial(, false, DefaultDialTimeout)
}
// DialTimeout dials the given TCP addr using tcp4 using the given timeout.
//
// This function has the following additional features comparing to net.Dial:
//
// - It reduces load on DNS resolver by caching resolved TCP addressed
// for DNSCacheDuration.
// - It dials all the resolved TCP addresses in round-robin manner until
// connection is established. This may be useful if certain addresses
// are temporarily unreachable.
//
// This dialer is intended for custom code wrapping before passing
// to Client.Dial or HostClient.Dial.
//
// For instance, per-host counters and/or limits may be implemented
// by such wrappers.
//
// The addr passed to the function must contain port. Example addr values:
//
// - foobar.baz:443
// - foo.bar:80
// - aaa.com:8080
func ( *TCPDialer) ( string, time.Duration) (net.Conn, error) {
return .dial(, false, )
}
// DialDualStack dials the given TCP addr using both tcp4 and tcp6.
//
// This function has the following additional features comparing to net.Dial:
//
// - It reduces load on DNS resolver by caching resolved TCP addressed
// for DNSCacheDuration.
// - It dials all the resolved TCP addresses in round-robin manner until
// connection is established. This may be useful if certain addresses
// are temporarily unreachable.
// - It returns ErrDialTimeout if connection cannot be established during
// DefaultDialTimeout seconds. Use DialDualStackTimeout for custom dial
// timeout.
//
// This dialer is intended for custom code wrapping before passing
// to Client.Dial or HostClient.Dial.
//
// For instance, per-host counters and/or limits may be implemented
// by such wrappers.
//
// The addr passed to the function must contain port. Example addr values:
//
// - foobar.baz:443
// - foo.bar:80
// - aaa.com:8080
func ( *TCPDialer) ( string) (net.Conn, error) {
return .dial(, true, DefaultDialTimeout)
}
// DialDualStackTimeout dials the given TCP addr using both tcp4 and tcp6
// using the given timeout.
//
// This function has the following additional features comparing to net.Dial:
//
// - It reduces load on DNS resolver by caching resolved TCP addressed
// for DNSCacheDuration.
// - It dials all the resolved TCP addresses in round-robin manner until
// connection is established. This may be useful if certain addresses
// are temporarily unreachable.
//
// This dialer is intended for custom code wrapping before passing
// to Client.Dial or HostClient.Dial.
//
// For instance, per-host counters and/or limits may be implemented
// by such wrappers.
//
// The addr passed to the function must contain port. Example addr values:
//
// - foobar.baz:443
// - foo.bar:80
// - aaa.com:8080
func ( *TCPDialer) ( string, time.Duration) (net.Conn, error) {
return .dial(, true, )
}
func ( *TCPDialer) ( string, bool, time.Duration) (net.Conn, error) {
.once.Do(func() {
if .Concurrency > 0 {
.concurrencyCh = make(chan struct{}, .Concurrency)
}
if .DNSCacheDuration == 0 {
.DNSCacheDuration = DefaultDNSCacheDuration
}
go .tcpAddrsClean()
})
:= time.Now().Add()
, , := .getTCPAddrs(, , )
if != nil {
return nil,
}
:= "tcp4"
if {
= "tcp"
}
var net.Conn
:= uint32(len())
for > 0 {
, = .tryDial(, &[%], , .concurrencyCh)
if == nil {
return , nil
}
if == ErrDialTimeout {
return nil,
}
++
--
}
return nil,
}
func ( *TCPDialer) ( string, *net.TCPAddr, time.Time, chan struct{}) (net.Conn, error) {
:= time.Until()
if <= 0 {
return nil, ErrDialTimeout
}
if != nil {
select {
case <- struct{}{}:
default:
:= AcquireTimer()
:= false
select {
case <- struct{}{}:
case <-.C:
= true
}
ReleaseTimer()
if {
return nil, ErrDialTimeout
}
}
defer func() { <- }()
}
:= net.Dialer{}
if .LocalAddr != nil {
.LocalAddr = .LocalAddr
}
, := context.WithDeadline(context.Background(), )
defer ()
, := .DialContext(, , .String())
if != nil && .Err() == context.DeadlineExceeded {
return nil, ErrDialTimeout
}
return ,
}
// ErrDialTimeout is returned when TCP dialing is timed out.
var ErrDialTimeout = errors.New("dialing to the given TCP address timed out")
// DefaultDialTimeout is timeout used by Dial and DialDualStack
// for establishing TCP connections.
const DefaultDialTimeout = 3 * time.Second
type tcpAddrEntry struct {
addrs []net.TCPAddr
addrsIdx uint32
pending int32
resolveTime time.Time
}
// DefaultDNSCacheDuration is the duration for caching resolved TCP addresses
// by Dial* functions.
const DefaultDNSCacheDuration = time.Minute
func ( *TCPDialer) () {
:= 2 * .DNSCacheDuration
for {
time.Sleep(time.Second)
:= time.Now()
.tcpAddrsMap.Range(func(, interface{}) bool {
if , := .(*tcpAddrEntry); && .Sub(.resolveTime) > {
.tcpAddrsMap.Delete()
}
return true
})
}
}
func ( *TCPDialer) ( string, bool, time.Time) ([]net.TCPAddr, uint32, error) {
, := .tcpAddrsMap.Load()
, := .(*tcpAddrEntry)
if && && != nil && time.Since(.resolveTime) > .DNSCacheDuration {
// Only let one goroutine re-resolve at a time.
if atomic.SwapInt32(&.pending, 1) == 0 {
= nil
}
}
if == nil {
, := resolveTCPAddrs(, , .Resolver, )
if != nil {
, := .tcpAddrsMap.Load()
, = .(*tcpAddrEntry)
if && && != nil {
// Set pending to 0 so another goroutine can retry.
atomic.StoreInt32(&.pending, 0)
}
return nil, 0,
}
= &tcpAddrEntry{
addrs: ,
resolveTime: time.Now(),
}
.tcpAddrsMap.Store(, )
}
:= atomic.AddUint32(&.addrsIdx, 1)
return .addrs, , nil
}
func resolveTCPAddrs( string, bool, Resolver, time.Time) ([]net.TCPAddr, error) {
, , := net.SplitHostPort()
if != nil {
return nil,
}
, := strconv.Atoi()
if != nil {
return nil,
}
if == nil {
= net.DefaultResolver
}
, := context.WithDeadline(context.Background(), )
defer ()
, := .LookupIPAddr(, )
if != nil {
return nil,
}
:= len()
:= make([]net.TCPAddr, 0, )
for := 0; < ; ++ {
:= []
if ! && .IP.To4() == nil {
continue
}
= append(, net.TCPAddr{
IP: .IP,
Port: ,
Zone: .Zone,
})
}
if len() == 0 {
return nil, errNoDNSEntries
}
return , nil
}
var errNoDNSEntries = errors.New("couldn't find DNS entries for the given domain. Try using DialDualStack")
![]() |
The pages are generated with Golds v0.6.7. (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 @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |