@@ -228,6 +228,13 @@ type Client struct {
228228 // By default connection duration is unlimited.
229229 MaxConnDuration time.Duration
230230
231+ // TCPKeepalivePeriod is the duration the connection needs to
232+ // remain idle before TCP starts sending keepalive probes.
233+ //
234+ // This field is only effective when TCPKeepalive is set to true.
235+ // A zero value indicates that the operating system's default setting will be used.
236+ TCPKeepalivePeriod time.Duration
237+
231238 // Maximum number of attempts for idempotent calls.
232239 //
233240 // DefaultMaxIdemponentCallAttempts is used if not set.
@@ -315,6 +322,14 @@ type Client struct {
315322
316323 // StreamResponseBody enables response body streaming.
317324 StreamResponseBody bool
325+
326+ // Whether the operating system should send tcp keep-alive messages on the tcp connection.
327+ //
328+ // By default tcp keep-alive connections are disabled.
329+ //
330+ // This option is used only if default TCP dialer is used,
331+ // i.e. if Dial and DialTimeout are blank.
332+ TCPKeepalive bool
318333}
319334
320335// Get returns the status code and body of url.
@@ -527,6 +542,8 @@ func (c *Client) Do(req *Request, resp *Response) error {
527542 MaxConns : c .MaxConnsPerHost ,
528543 MaxIdleConnDuration : c .MaxIdleConnDuration ,
529544 MaxConnDuration : c .MaxConnDuration ,
545+ TCPKeepalivePeriod : c .TCPKeepalivePeriod ,
546+ TCPKeepalive : c .TCPKeepalive ,
530547 MaxIdemponentCallAttempts : c .MaxIdemponentCallAttempts ,
531548 ReadBufferSize : c .ReadBufferSize ,
532549 WriteBufferSize : c .WriteBufferSize ,
@@ -796,6 +813,13 @@ type HostClient struct {
796813 // By default will not waiting, return ErrNoFreeConns immediately
797814 MaxConnWaitTimeout time.Duration
798815
816+ // TCPKeepalivePeriod is the duration the connection needs to
817+ // remain idle before TCP starts sending keepalive probes.
818+ //
819+ // This field is only effective when TCPKeepalive is set to true.
820+ // A zero value indicates that the operating system's default setting will be used.
821+ TCPKeepalivePeriod time.Duration
822+
799823 // Connection pool strategy. Can be either LIFO or FIFO (default).
800824 ConnPoolStrategy ConnPoolStrategyType
801825
@@ -871,6 +895,16 @@ type HostClient struct {
871895 StreamResponseBody bool
872896
873897 connsCleanerRun bool
898+
899+ // Whether to enable tcp keep-alive connections.
900+ //
901+ // Whether the operating system should send tcp keep-alive messages on the tcp connection.
902+ //
903+ // By default tcp keep-alive connections are disabled.
904+ //
905+ // This option is used only if default TCP dialer is used,
906+ // i.e. if Dial and DialTimeout are blank.
907+ TCPKeepalive bool
874908}
875909
876910type clientConn struct {
@@ -1886,6 +1920,22 @@ func (c *HostClient) dialHostHard(dialTimeout time.Duration) (conn net.Conn, err
18861920 // use dialTimeout to control the timeout of each dial. It does not work if dialTimeout is 0 or if
18871921 // c.DialTimeout has not been set and c.Dial has been set.
18881922 // attempt to dial all the available hosts before giving up.
1923+ if c .Dial == nil && c .DialTimeout == nil && c .TCPKeepalive {
1924+ d := & TCPDialer {Concurrency : defaultDialer .Concurrency , TCPKeepalive : true , TCPKeepalivePeriod : c .TCPKeepalivePeriod }
1925+ if dialTimeout > 0 {
1926+ if c .DialDualStack {
1927+ c .DialTimeout = d .DialDualStackTimeout
1928+ } else {
1929+ c .DialTimeout = d .DialTimeout
1930+ }
1931+ } else {
1932+ if c .DialDualStack {
1933+ c .Dial = d .DialDualStack
1934+ } else {
1935+ c .Dial = d .Dial
1936+ }
1937+ }
1938+ }
18891939
18901940 c .addrsLock .Lock ()
18911941 n := len (c .addrs )
@@ -2326,6 +2376,12 @@ type pipelineConnClient struct {
23262376 WriteBufferSize int
23272377 ReadTimeout time.Duration
23282378 WriteTimeout time.Duration
2379+ // TCPKeepalivePeriod is the duration the connection needs to
2380+ // remain idle before TCP starts sending keepalive probes.
2381+ //
2382+ // This field is only effective when TCPKeepalive is set to true.
2383+ // A zero value indicates that the operating system's default setting will be used.
2384+ TCPKeepalivePeriod time.Duration
23292385
23302386 chLock sync.Mutex
23312387
@@ -2335,6 +2391,14 @@ type pipelineConnClient struct {
23352391 DisableHeaderNamesNormalizing bool
23362392 DisablePathNormalizing bool
23372393 IsTLS bool
2394+
2395+ // Whether the operating system should send tcp keep-alive messages on the tcp connection.
2396+ //
2397+ // By default tcp keep-alive connections are disabled.
2398+ //
2399+ // This option is used only if default TCP dialer is used,
2400+ // i.e. if Dial is blank.
2401+ TCPKeepalive bool
23382402}
23392403
23402404type pipelineWork struct {
@@ -2666,6 +2730,14 @@ func (c *pipelineConnClient) init() {
26662730
26672731func (c * pipelineConnClient ) worker () error {
26682732 tlsConfig := c .cachedTLSConfig ()
2733+ if c .TCPKeepalive && c .Dial == nil {
2734+ d := & TCPDialer {Concurrency : defaultDialer .Concurrency , TCPKeepalive : true , TCPKeepalivePeriod : c .TCPKeepalivePeriod }
2735+ if c .DialDualStack {
2736+ c .Dial = d .DialDualStack
2737+ } else {
2738+ c .Dial = d .Dial
2739+ }
2740+ }
26692741 conn , err := dialAddr (c .Addr , c .Dial , nil , c .DialDualStack , c .IsTLS , tlsConfig , 0 , c .WriteTimeout )
26702742 if err != nil {
26712743 return err
0 commit comments