学习笔记 HTTP权威指南 第4章 TCP连接

175 阅读9分钟

上一章讲了报文,如果要查看一个网页,光有报文不得行,必须把报文从服务器发到客户端才行.而所有报文都是通过TCP连接发送的.所以这章介绍了TCP连接的工作方式,及存在的问题和优化方法

4.1 TCP连接

  • HTTP通信都是由TCP/IP承载的.
  • TCP/IP是分组交换网络分层协议集
    • 分组交换
      • 把数据分成组后发送交换
    • 网络分层协议
      • 是几个不同层次的协议
      • 由很多协议组成

    4.1.1 TCP的可靠数据管道

    TCP为HTTP提供了一条可靠的比特数据传输管道
    • 字节流会从一端有序的进去
    • 然后从另一端有序列的流出

4.1.2 TCP流是分段的,由IP分组传送

  • TCP数据流: HTTP把报文传输给TCP后,TCP会将报文分成一个个小段,就叫TCP流
  • TCP段: TCP在TCP数据流中添加TCP首部后的数据,就是TCP段,然后将其传递给IP
  • IP分组:IP收到TCP段后,会在里面添加IP首部,组成的数据就叫IP分组,然后再将IP分组发送到其他电脑上
  • IP分组的内容:
    • IP分组首部
    • TCP段首部
    • TCP数据块/流

4.1.3 维持TCP连接

  • 源IP地址 + 源端口
  • 目标IP地址 + 目标端口

4.1.4 用TCP套接字编程

  • 是什么: 是操作TCP连接的工具
  • 有什么用:
    • 创建TCP站点
    • 将端点与远程服务器连接
    • 读写数据流
  • 如何工作:
    • 隐藏握手细节
    • 隐藏TCP流的分段和重组细节

4.2 TCP性能瓶颈

4.2.1 HTTP事务的时延

从完成一个HTTP事务的各个环节,都存在延迟的可能

  • DNS解析延时
    • 新访问一个域名,没有解析缓存,首次解析花的时间长
  • 建立TCP连接延时
    • 每个请求都会建立一个连接,请求多时延迟高
  • 传输/处理报文延时
    • 慢启动机制
  • 响应报文延时
    • 数据聚集算法
    • 延迟确认算法

4.2.3 TCP连接的握手延时

建立TCP连接需要3次握手,如果握3次手,就为了传1kb数据,就非常不划算了

  • 现代浏览器都在最后一次握手时,直接把数据带上
  • 服务器在第2次握手时,也可以携带数据

4.2.4 延迟确认

  • IP分组的传送逻辑

    • 每个TCP段都包含一个序列号和完整性检验和
    • 接收方每收到一个TCP段后,会发一个确认分组
    • 发送者收到确认分组后表示传送OK
  • 什么是延迟确认

    • 服务器把数据准备好后,先不响应给客户端,而是放在缓存里面
    • 等200ms左右
    • 如果有确认分组的报文,就让它捎个顺风车回去
    • 如果超过200ms还没有顺风车,才直接发一个响应回去
  • 为什么要延迟确认

    • 因为确认分组收到的响应报文,本身的信息量非常小,相当于发空车
    • 还可以携带更多的数据
    • 就可以利用这个条件搭个便车,减少流量
  • 延迟确认存在的问题

    • 双峰特征导致白白的等待
      • 数据发送的越多,TCP段确认就越多
      • 但是延迟等待,会减少数据的发送
      • 这样TCP段的确认就变少了
      • 延迟后就很难搭到顺风车,等了半天没有顺风车,最后还是要自己开车,就浪费了很多时间

4.2.5 TCP慢启动

  • 什么是慢启动

    • 连接建立后,开始传输的流量很少
    • 时间越长,可以传输的流量越多
    • 有点类似于信用卡,用得越多,客户就越高
  • 为什么需要慢启动

    • 防止网络突然过载和拥塞
  • 存在的问题

    • 新连接的传输速度特别慢

4.2.6 Nagle算法

  • 什么是Nagle算法

    • 在发送一个IP分组之前
    • 将大量TCP数据绑定在一起发送
    • 不够或没确认的时候,就先不发
  • 为什么需要Nagle算法

    • 如果一个IP分组只发一丁点儿TCP数据流
    • 就非常浪费资源
    • 有点类似于确认收到TCP段的响应一样
  • 存在的问题

    • 有可能响应本身就只有一丁点儿数据,永远等不到其他数据一起回去,就白等了
    • 延迟算法会延迟确认分组,而Nagle又在等它延迟完了再打包,就是慢上加慢了

4.2.7 TIME_WAIT累积和端口耗尽

什么是TIME_WAIT

  • 在链接关闭一段时间内
  • 维护一张IP端口表
  • 在这段时间内禁用这些端口

为什么需要TIME_WAIT

  • 因为第一个TCP链接都要不同的IP+端口组合
  • 防止在同一时间端口重用
  • 导致报文出错

为什么端口会耗尽

  • 源端口总数有限
  • 而在固定的TIME_OUT内又不能重用
  • 所以导致每秒的可用端口数量只有几百个
  • 如果连接长时间不释放,可用的更少

4.3 HTTP连接的处理

4.3.1 Connection首部

  • 可设置的值

    • 其他HTTP首部字段名
    • 任意标签值,相当于自定义描述
    • close,用于关闭持久连接
  • 工作机制

    • 接收端会解析所有收到的请求首部
    • 删除Connection及Connection里面提到的首部
    • 删除逐跳首部

4.3.2 串行事务延时

  • 串行事务为什么会延时

    • 串行的建立连接,握手,慢启动都会叠加起来
    • 页面上有多个资源时,其他资源一直处于等待状态,视觉效果感觉是白屏
    • 数据加载前,浏览器会处理空白状态,视觉上会产生卡的现象
  • 怎么解决串行延时

    • 并行连接: 同时建立多条TCP链接发起请求
    • 持久连接: 重用已建立的TCP连接,就不用等慢启动
    • 管道化连接: 多个HTTP共享一条TCP连接

4.4 并行连接

  • 为什么会比串行快

    • 串行连接会在一个TCP链接建立成功后再建立下一个
    • 并行则当第一个TCP连接开始后创建后,就马上创建.当然要省时一些
  • 为什么并行可能比串行慢

    • 当下行带宽不足时,多个并且连接会争抢仅有的带宽,导致都变慢.有点像一个和尚有水喝,3个和尚没水喝的道理
    • 维持多个TCP连接的开销肯定比单个TCP连接的开销要大
  • 为什么TCP连接让人感觉快一些

    • 串行连接在处理时,其他资源处于白屏状态,用户感觉是没动
    • 并行连接在处理时,所有资源都在慢慢的加载,虽然动的慢,但感觉上至少在动

4.5 持久连接

什么是站点局部性

  • 连接到一个网站后,还可能发起更多关于这个网站的请求,比如图片等

什么是持久连接

  • 连接建立后暂时不关闭
  • 后面的请求可以直接使用这条连接

持久连接的好处

  • 避免反复的3次握手
  • 避免连接开始的慢启动

存在的问题

  • 可能会产生大量的空闲连接
  • 影响服务器性能

4.5.1 持久以及并行连接

  • 持久连接的两种类型
    • HTTP/1.0里面的keep-alive
    • HTTP/1.1的persistent

4.5.2 keep-alive持久连接

  • 如何建立keep-alive持久连接

    • 客户端请求时添加首部Connection: keep-alive
    • 服务器响应时,返回Connection: keep-alive就可以建立连接
    • 否则表示服务器不劫持,响应后关闭连接
  • keep-alive选项

    • timeout: 响应首部里面的值,表示持久多长时间
    • max: 最多可以劫持的连接数量
    • 其他键值对,用于调试
Connection: Keep-Alive
keep-alive: max=5, timeout=120
  • keep-alive规则
    • 必须显示指定Connection: alvie才能打开持久连接
    • 每次HTTP连接都要带上Connection:keep-alive,否则会被关闭连接
    • 响应时如果不带Connection:keep-alive,表示关闭连接 ...其他参考P99

4.5.3 哑代理

  • 什么是盲中继

    • 是一个代理
    • 只是盲目的转发报文
    • 而不会对首部中在Connection做任何处理
  • 盲中继存在的问题

    • 它自己不会建立持久连接
    • 但是转发了Connection:keep-alive,让服务器和客户端务认为可以持久连接
    • 导致客户端和服务器会一直不停的向他发送消息
    • 而他又不会转发,所以客户端和服务器就请求超时
  • Proxy-connection的原理

    • 盲中继会转发Proxy-connection: keep-alive,服务器收到后会丢弃,所以服务器响应后就关闭了连接
    • 聪明的中继会把Proxy-connection修改成Connection:keep-alive转发,并且收到服务器的响应后会建立持久连接
  • Proxy-Connection的作用

    • 规避盲中继的问题
    • 可以在服务器和客户端中间搭建持久连接
  • Proxy-Connection的不足

    • 如果聪明中继和盲中继对上了
    • 这一招仍然不管用

4.5.4 HTTP/1.1持久连接

  • 特点

    • 默认开通持久链接
    • 必须显示的添加Connection:close关闭连接
  • 规则

    • 一个客户端对服务器最多维持2条持久连接 ...其他的参考书P104页

4.6 管道化连接

  • 什么是管道化连接

    • 第1条请求流出后
    • 第2,3,4条请求也开始发送
    • 和并行连接差不多,这里只是在并行请求而已
  • 管道化连接的好处

    • 在高延时网络下,可以降低环回时间,提高性能
  • 限制规则

    • 建立在持久连接基础之上
    • 只适合没有副作用的请求

4.7 关闭连接

4.7.1 连接随时可能关闭

  • 在哪些情况下会关闭连接

    • 报文结束时关闭
    • 解释出错时关闭
    • 其他任何情况,比如网络故障
  • 存在的问题

    • 客户端还在传数据时,发现服务器连接已经关闭了.就会出错

4.7.2 正常关闭连接

  • 什么是完全关闭

    • 调用close(),会关闭输入输出
  • 什么是半关闭

    • 调用shutdown()单独关闭输入或输出
  • 为什么关闭输入信道比较危险

    • 客户端请求时,如果服务器输入已经关闭
    • 服务器会回头一条重置报文
    • 然后删除已缓存的数据(这些数据有可能是已经上传了99%的图片,只是没保存而已)
  • 如何正常关闭

    • 先关闭输出信道
    • 等另一端关闭输出后再关闭输入
    • 或者等一段时间查询对方是否关闭,然后再完全关闭