上一章讲了报文,如果要查看一个网页,光有报文不得行,必须把报文从服务器发到客户端才行.而所有报文都是通过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%的图片,只是没保存而已)
-
如何正常关闭
- 先关闭输出信道
- 等另一端关闭输出后再关闭输入
- 或者等一段时间查询对方是否关闭,然后再完全关闭