golang http1.1代码实现

本文深入探讨了TCP连接的超时、连接池、持久连接以及Keepalive设置。重点讲解了Client、Transport、Dialer和Resolver的工作原理,包括TLS握手超时、IdleConnTimeout、MaxResponseHeaderBytes等关键参数。同时,详细阐述了TCP Keepalive的开启步骤、超时时间和间隔,并介绍了DNS解析过程和Resolver的行为。最后,提到了TLS的客户端和服务器握手过程,展示了TCP长连接如何维护其健康状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

涉及结构体

  1. Client、Transport、Dailer、Request、Resolver

Request

  1. ctx context.Context 可以设置超时时间

Client

  1. Timeout:整体超时设置,与Request的ctx取较小超时时间

Transport

  1. TLSHandshakeTimeout:tls握手的超时时间,通过AfterFunc实现,超时后,直接返回tlsHandshakeTimeoutError
  2. DisableKeepAlives:如果为true,不会有conn连接池,每次都是开启新连接,不会进行连接复用,与TCP的keep-alive没有关系
  3. persistConn的readLoop和writeLoop一个进行读数据,一个写数据
  4. MaxResponseHeaderBytes:获取返回的Header最大值,默认值为10M,返回的body没有限制,在persistConn里的Read函数实现
  5. IdleConnTimeout:conn放入Idle池中后,IdleConnTimeout时间仍未使用,直接关闭,通过TimeAfter函数执行关闭函数closeConnIfStillIdle。DefaultTransport里面给的是90s。默认是使用连接池,90s后没有使用就关闭连接

persistConn

  1. br和bw对应底层的persistConn和persistConnWriter,一个是reader,一个是writer。

    readLoop

    1. bodyEOFSignal:封装response,br读取完后,返回EOF的error,然后执行bodyEOFSignal的fn函数,然后通过waitForBodyRead信号量,将isEOF的信号传递给bodyEOF,执行一下代码,tryPutIdleConn确认是否退出for循环DisableKeepAlives为true和MaxIdleConnsPerHost,返回false,退出for循环

      select {
      case bodyEOF := <-waitForBodyRead:
      		replaced := pc.t.replaceReqCanceler(rc.cancelKey, nil) // before pc might return to idle pool
      		alive = alive &&
      			bodyEOF &&
      			!pc.sawEOF &&
      			pc.wroteRequest() &&
      			replaced && tryPutIdleConn(trace)
      		if bodyEOF {
      			eofc <- struct{}{}
      		}
      		...
      }
      
    2. 退出循环,会通过defer close persistConn

Dialer

  1. Timeout:获取conn的超时时间,与Request的ctx取较小超时时间。一般TCP的超时一般是3分钟

  2. DialContext

    • 先使用Resolver进行域名解析

    • 多个地址,每个连接的超时时间是平分的,通过partialDeadline实现

    • TCP实现dialTCP

    • UDP实现dialUDP

    • IP实现dialIP

    • socket连接超时使用的ctx

    • Keepalive参数:keepalive通过系统调用,将句柄设置keepalive的超时时间。keepalive开启分为

      两步

      • 通过系统调用将句柄的SO_KEEPALIVE字段设置为true
      • 通过系统调用设置超时时间,设置TCP_KEEPINTVl字段和TCP_KEEPIDLE字段,TCP_KEEPINTVl默认为15,linux系统为75,TCP_KEEPIDLE默认为15s
      • 涉及字段为KeepAlive、tcp_keepalive_time、tcp_keepalive_intvl、tcp_keepalive_probes
        • KeepAlive:是否开启keepalive这一功能选项
        • tcp_keepalive_time:tcp可以保持的空闲时间,即发送一次探针成功后,可以保证这个TCP这么长的时间是活的
        • tcp_keepalive_intvl:探针发送的周期
        • tcp_keepalive_probes:如果tcp_keepalive_time这么久没有收到探针,则再发送tcp_keepalive_time次数探活测试包包,如果都失败,则表明这个TCP连接已经挂了

Resolver

  1. lookupIPAddr:获取IP地址数组
  2. parseIPZone直接解析ip地址,不走dns
  3. 实际调用的函数为lookupIP
  4. PreferGo默认为false,实际最后都是调用goLookupIPCNAMEOrder,两种方式直接获取的order的不太一样
    • prefergo
      • true:只从systemConf里面获取Oder
      • false:先从systemConf里面获取Oder,如果为hostLoopupCgo,则Cgo的方式获取
    • 读取/etc/nsswitch.conf、/etc/resolv.conf和/etc/mdns.allow
    • order有下面几种类型
      • hostLookupCgo
      • hostLoopupFilesDNS
      • hostLoopupDNSFiles
      • hostLoopupFiles
      • hostLoopupDNS
    • goLoopupIPCNAMEOrder
    • 域名最大长度255
    • 可以通过配置resolv.conf的useTCP强制使用TCP,否则先通过udp获取,获取不到再使用tcp
    • dns的超时时间默认为5s,如果在resolv.conf配置了,使用配置中的
    • 调用远端的dailer也是Dialer

TLS

  1. persistConn.addTLS:添加tls
  2. 握手
    • clientHandshake
    • serverHandshake

学习文章

  1. keepalive
  2. 理解TCP长连接Keepalive)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值