HTTP个人总结(三)

今天来总结的是关于HTTP的连接管理。

首先来介绍TCP连接是什么?
这里写图片描述
TCP为HTTP提供了一条可靠的比特传输通道,从TCP连接一端填入的字节会从另一端以原有的顺序、正确地传送出来。

TCP是分流的、由IP分组传送又是什么?

TCP的数据是通过名为IP分组的小数据块来发送的,HTTPS就是在HTTP和TCP之间插入了一个(称为TLS或SSL的)密码加密层。
这里写图片描述
HTTP要传送一条报文时,会以流的形式将报文数据的内容通过一条打开的TCP连接按序传输。TCP收到数据流之后,会将数据流之后,会将数据流砍成被称作段的小数据块,并将段封装在IP分组中,通过因特网进行传输,所有这些工作都是由TCP/ip软件来处理的,程序员什么都看不到。
这里写图片描述
每个TCP段都是由IP分组承载,从一个IP地址发送到另一个IP地址,每个IP分组中包括:
1.一个IP分组首部(通常为20字节)
2.一个TCP段首部(通常为20字节)
3.一个TCP数据块(0个或多个字节)
IP首部包含了源和目的IP地址、长度和其他一些标记,TCP段的首部包含了TCP端口号,TCP控制标记以及用于数据排序和完整性检查的一些数字值。

下面介绍用TCP套接字编程?

操作系统提供了一些操纵其TCP连接的工具。
这里写图片描述
这个套接字API隐藏了TCP和IP所有细节。套接字API允许用户创建TCP的端点数据结构,将这些端点与远程服务器的TCP端口进行连接,并对数据流进行读写。TCP API隐藏了所有底层网络协议的握手细节,以及TCP数据流与IP分组之间的分段和重组细节。
这里写图片描述
我们从Web服务器等待连接开始,客户端根据URL判定出IP地址和端口号,并建立一条到服务器的TCP连接。建立连接可能要花费一些时间,时间长短取决于服务器距离的远近、服务器的负载情况以及因特网的拥挤程度。一旦建立连接,就可以进行客户端与服务器的交互。

对TCP性能的考虑?

HTTP事务的性能在很大程度上取决于底层TCP通道的性能。
如HTTP事务的时延:
这里写图片描述
注意,与建立TCP连接,以及传输请求和响应报文的时间相比,事务处理时间可能是很短的。HTTP事务时延的几种主要原因:
1.客户端首先需要根据URI确定Web服务器的IP地址和端口号,如果最近没有对URI中的主机名进行访问,通过DNS解析系统将URI主机名转换成一个IP地址可能要花费数十秒的时间。
2.客户端会向服务器发送一条TCP连接请求,并等待服务器回送一个请求接收应答,每条新的TCP连接都会有连接建立时延,这个值通常最多只有一两秒钟,但如果有数百个HTTP事务的话,这个值就会快速叠加起来。
3.一旦建立连接,客户端就会通过新建立的TCP管道来发送HTTP请求。数据到达,Web服务器会从TCP连接中读取请求报文,并对请求进行处理,因特网传输请求报文,以及服务器处理请求报文都需要时间。
4.Web服务器回送响应报文也需要时间。

下面列出会对程序员产生影响的最常见的TCP相关时延:
1.TCP连接建立握手
2.TCP慢启动拥塞控制
3.数据聚集的Nagle算法
4.用于捎带确认的TCP延迟确认算法
5.TIME_WAIT时延和端口耗尽

下面进行各个原因的详细介绍:
首先介绍TCP连接的握手时延:
这里写图片描述
需要经历以下步骤:
1.请求新的TCP连接时,客户端要向服务器发送一个小的TCP分组,这个分组中设置了一个特殊的SYN标记,说明这是一个连接请求。
2.如果服务器接收了连接,就会对一些连接参数进行计算,并向客户端回送一个TCP分组,这个分组中的SYN的ACK标记都被置位,说明连接请求已被接收。
3.最后,客户端向服务器回送一条确认小心,通知它连接已成功建立。现代的TCP栈都允许客户端在这个确认分组中发送数据。

接下来介绍TCP慢启动:
TCP数据传输的性能还取决于TCP连接的使用期。TCP连接会随着时间进行自我“调整”。起初会限制连接的最大速度,如果数据成功传输、会随着时间的推移提高传输的速度。用于防止因特网的突然过载和拥塞。

然后是Nagle算法与TCP_NODELAY:
TCP有一个数据流接口,应用程序可以通过它将任意尺寸的数据放入TCP栈中——即使一次只放一个字节也可以,但是每个TCP段中都至少装载了40个字节的标记和首部,所以如果TCP发送大量包含少量数据的分组,网络性能就会严重下降。
Nagle算法鼓励发送全尺寸(LAN上最大尺寸的分组约是1500字节,在因特网上是几百字节)的端,只有当所有其他分组都被确认之后,Nagle算法才允许发送非全尺寸的分组,如果其他分组仍然在传输过程中,将要将那部分数据缓存起来,只有当挂起分组被确认,或者缓存中积累了足够发送一个全尺寸分组的数据时,才会将缓存的数据发送出去。
Nagle算法会引发几种HTTP性能问题,首先,小的HTTP报文可能无法填满一个分组,可能会因为等待那些永远不会到来的额外数据而产生时延,其次,Nagle算法与延迟确认之间的交互存在问题——Nagle算法会阻止数据的发送,知道有确认分组抵达为止,但确认分组自身会被延迟确认算法延迟100~200毫秒。
HTTP可以再自己的栈中设置参数TCP_NODELAY,禁止Nagle算法,提高性能,弹药保证会向TCP写入大块的数据。

接下来是用于捎带确认的TCP延迟确认算法。由于因特网自身无法确认可靠的分组传输(因特网路由器超负荷的话,可以随意丢弃分组),所有TCP实现了自己的确认机制来确保数据的成功传输。
每个TCP段都有一个序列号和数据完整性校验和,每个段的接受者收到完好的端时,都会向发送者回送小的确认分组,如果发送者没有在指定窗口时间内收到确认消息,发送者就认为分组已被破坏或损毁,并重发数据。
由于确认报文很小,所以TCP允许在发往相同方向的输出数据分组中对其进行“捎带”,TCP将返回确认信息与输出的数据分组结合在一起,可以有效的利用网络。为了增加确认报文找到同向传输数据分组的可能性,很多TCP栈都实现了一种“延迟确认”的算法。延迟确认算法会在一个特定的窗口时间内将输出确认存放在缓冲区,以寻找到能够捎带它的输出数据分组,如果在那个时间段内没有输出数据分组,就将确认信息放在单独的分组中发送。但是这个延迟确认算法会引入相当大的延迟,所以根据操作系统的不同,可以调整或者禁止这个算法。

最后介绍TIME_WAIT累积和端口耗尽:
TIME_WAIT端口耗尽时很严重的性能问题,会影响到性能基准,但现实中相对较少出现,大多数遇到性能基准问题的人最终都会碰到这个问题。
当某个TCP端点关闭TCP连接时,会在内存中维护一个小的控制块,用来记录最近所关闭连接IP地址和端口号,这类信息只会维持一小段时间,通常是所顾忌的最大分段使用期的两倍(称为2MSL,通常是2分钟)左右,以确保在这段时间内不会创建具有相同地址和端口号的新连接,就是昂志在两分钟内创建、关闭并重新创建两个具有相同IP地址的端口号的连接。
这个通常不是什么问题,但是在性能基准环境下可能会成为一个问题。进行性能基准测试时,通过只有一台或几台来产生流量的计算机连接到某系统中去,这样就限制了连接到服务器的客户端IP地址数,而且服务器通常会在HTTP的默认TCP端口80上进行监听。
在只有一个客户端和一台Web服务器的异常情况下,构建一条TCP连接的4个值:
source-IP-address,source-port,destination-IP-adress,destination-port
其中三个是固定的,只有源端口号可以随便改变,客户端每次连接到服务器上去是,都会获得一个新的端口,以实现连接的唯一性,但是由于可用源端口的数量有限(比如60000个),而且在2MSL秒(比如120秒)内连接是无法重用的,连接率就被限制在了60000/120=500次/秒,要修正这个问题,可以增加客户端负载生成机器的数量或者确保客户端和服务器在循环使用几个虚拟IP地址以增加更多的连接组合。
当大量端口连接处于打开状态的情况,有些操作系统的速度会严重减缓。

下面介绍HTTP连接的处理?

串行事务处理时延:
如果只对连接进行简单的管理,TCP性能时延可能会叠加起来,比如一个页面请求4个HTTP事务,如果每个事务都需要(串行地建立)一条新的连接,那么连接时延和慢启动时延就会叠加起来。
这里写图片描述
串行加载的另一个缺点:有些浏览器在对象加载完毕之前无法获知对象的尺寸,而且他们可能需要尺寸信息来决定将对象放在屏幕上的什么位置,所以在加载了足够多的对象之前,无法再屏幕上显式任何内容,在这种情况下,可能浏览器串行装载对象的进展很正常,但是用户面对面的确实一个空白的屏幕,对装载的进度一无所知。

还有几种可以提高HTTP连接性能的技术:
1.并行连接:通过多次TCP连接发起并行地HTTP请求
2.持久连接:重用TCP连接,以消除连接及关闭时延
3.管道化连接:通过共享的TCP连接发起的并发的HTTP请求
4.复用的连接:交替传送请求和响应报文(实验阶段)

下面进行详细介绍:
并行连接:
HTTP允许客户端打开多条连接,并行地执行多个HTTP事务。如:
这里写图片描述
这里写图片描述
但是并行速度并不一定总是更快,如果客户端的网络带宽不足,一个连接到速度较快的服务器上的HTTP的事务耗尽了所有可用的带宽,那么每个对象都会以较慢的速度按比例加载,这样带来的性能提升很小,甚至没有,而且打开大量连接消耗更多的内存资源,从而引发自身的性能问题。但是即使没有增快,但是给用户觉得页面加载更快,因为多个组件对象同时出现在屏幕上,用户可以看到加载的进展。
并行地缺点:
1.每个事务都会打开/关闭一条新的连接,会耗费时间和带宽
2.由于TCP慢启动特性的存在,每条新连接的性能都会有所下降
3.可打开的并行连接数量实际上是有限的

持久连接:
HTTP/1.1(以及HTTP/1.0的各种增强版本)允许HTTP设备在事务处理结束之后将TCP连接保持在打开状态,以便为未来的HTTP请求重用现存的连接,这叫持久连接。
重用已对目标服务器打开的空闲持久连接,就可以避开缓慢的连接建立阶段,而且已经打开的连接还可以避免慢启动的拥塞适应阶段,以便更快速的进行数据的传输。
持久连接与并行连接配合使用可能是最高效的方式。比较老的HTTP/1.0+使用“keep-alive”连接,HTTP/1.1使用persistent连接
这里写图片描述
keep-alive已经不再使用了,而且在当前的HTTP/1.1规范中也没有对它的说明了。但浏览器和服务器丢keep-alive握手的使用仍然相当广泛,因此HTTP实现者应该做好与之交互操作的准备。客户端可以通过包含contection:keep-alive首部请求将一条连接保持在打开状态,如果服务器愿意为下一条连接请求将连接保持在打开状态,将在响应中包含相同的首部,如:
这里写图片描述
keep-alive首部只是请求将连接保持在活跃状态,客户端和服务器不一定会同意keep-alive会话,它们可以在任意时刻关闭空闲的keep-alive连接,并可以随意限制keep-alive连接所处理事务的数量。

下面介绍的是keep-alive和哑代理?

首先先介绍connection首部和盲中继:
盲中继:它们只是将字节从一个连接转发到另一个连接中去,不对connection首部进行特殊的处理,如:
这里写图片描述
图中发生了如下的问题:
1.Web客户端向代理发送了一条报文,其中包含了connetion:keep-alive首部,如果可能的话请求建立一条keep-alive连接。客户端等待响应,以确定对方是否认可它对keep-alive信道的请求
2.哑代理收到了这条HTTP请求,但它不理解Connection首部(只是将它当做一个扩展首部对待),因此只是沿着转发链路将报文一字不漏地发送给服务器,但Connection首部是个逐跳首部,只适用于单条传输链路
3.经过中继的HTTP请求抵达了Web服务器,当Web服务器收到经过代理转发的Connection:Keep-alive首部时,会误以为代理(对服务器来说,这个代理看起来就和其他客户端一样)希望进行keep-alive对话,Web服务器会送了一个Connection:keep-alive响应首部,所以此时Web服务器认为他在和代理进行keep-alive对话,遵循keep-alive规则,但代理其实却对keep-alive一无所知
4.哑代理将Web服务器的响应报文回送给客户端,并将来自Web服务器的Connection:keep-alvie首部一起传送回去。客户端看到这个首部就会认为代理同意了keep-alive对话,此时客户端和服务器都认为它们在进行keep-alive对话,但是与它们进行对话的代理却对keep-alive一无所知
5.由于代理对于keep-alive一无所知,所以会将收到的所有数据都回送给客户端,然后等源端服务器关闭连接。但源端服务器会认为代理已经显示的请求它连接保持在打开状态,所以不会去关闭连接,这样代理会挂在那里等待连接关闭。
6.客户端收到回送的响应报文,会立即转向下一条请求,在keep-alive连接上向代理发送另一条请求,而代理并不认为同一条连接上会有其他请求到来,请求被忽略,浏览器就在这里转圈,不会有任何进展
7.这种错误的通信方式会使浏览器一直处于挂起状态,直到客户端或服务器将连接超时,并将其关闭。

为避免此类代理通信问题,现代的代理都决不能转发Connection首部和所有名字出现connection值中的首部。

为了解决这个问题,引入了一个名为Proxy-connection的新首部,解决了客户端后面紧跟着一个盲中继所带来的问题——但没有解决所有其他情况下存在的问题。
所以之后会出现这种情况:浏览器会向代理发送非标准的Proxy-Connection扩展首部。如果代理是盲中继,它将会无意义的Proxy-connnection首部转发给Web服务器,服务器会忽略此首部,不会带来任何问题,但如果代理是聪明的(能够理解持久连接的握手动作),就会使用一个Connection首部取代无意义的Proxy-connection首部,然后将其发送给服务器,以收到预期的效果。
这里写图片描述
但如果在哑代理任意一侧还有一个聪明的代理,那么问题又会产生:
这里写图片描述

下面介绍HTTP/1.1持久连接?

HTTP/1.1逐渐停止了对keep-alive连接的支持,用一种名为持久连接(persisetent connection)的改进型。与HTTP/1.0的keep-alive连接不同,HTTP/1.1假定所有连接都是持久的,要在事务处理结束之后将连接关闭,HTTP/1.1应用程序必须向报文显式地增加一个Connection:close首部,但是客户端和服务器仍然可以随时关闭空闲的连接。

接下来介绍管道化连接?

HTTP/1.1允许在持久连接上可选地使用请求管道。在响应到达之前,可以将多条请求放入队列,当第一条请求通过网络流向服务器时,第二条和第三条也可以开始发送了。在高延时的网络条件下,这样做可以降低网络的环回时间,提高性能。
这里写图片描述

最后来介绍关闭连接?

所有的HTTP客户端、服务器或代理都可以在任意时刻关闭一条TCP传输连接。服务器永远都无法确定在它关闭“空闲”连接那一段时间,在线路的那一头客户端有没有数据要发送。如果出现这种情况,客户端就会在写入半截请求报文时发现出现了连接错误。
即使在非错误情况下,连接也可以任意时刻关闭。HTTP应用横须要做好正确处理非预期关闭的准备,如果在客户端执行事务的过程中,传输连接关闭了,那么除非事务处理会带来一些副作用,否则客户端应该重新打开连接,并重试一次。
副作用指的是如幂等性问题。如果一个事务,不管是执行一次还是很多次,得到的结果都相同,这个事务就是幂等的,要发送一条非幂等性请求,就需要等待来自前一条请求的响应。正确关闭连接时,TCP连接是双向的,如:
这里写图片描述
有完全关闭:套接字调用close()
半关闭:套接字调用shutdown()
如:
这里写图片描述
关闭连接的输出信道总是安全的,连接另一端的对等实体会在其缓冲区中读出所有数据之后收到一条通知,说明流结束了,这样他就知道你将连接关闭了。
关闭连接的输入信道比较危险,除非你知道另一端不打算再发送其他数据了,如果另一端向你已关闭的输入信道发送数据,操作系统就会向另一端机器会送一条TCP”连接被对端重置”的报文,大部分操作系统都会删除对端还未读取的所有缓存数据。
这里写图片描述
比如你已经在一条持久连接上发送了10条管道式请求了,响应也已经收到了,正在操作系统的缓冲区中存着(但应用程序还未将其读走)。现在假设你发送第11条请求,但服务器认为你使用这条连接的时间已经够长了,决定将其关闭,那么你的第11条请求就会被发送到一条已关闭的连接上去,并会向你会送一条重置信息,这个重置信息会清空你的输入缓冲区,当你最终去读取数据的时候,会得到一个连接被对端重置的错误,已缓存的未读响应数据都丢失了,尽管其中大部分都已经成功抵达你的机器了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值