HTTP协议及TCP分析

1. Http是无状态协议

HTTP是一种不保存状态,即无状态(stateless)协议。HTTP协议自身不对请求和响应之间的通信状态进行保存。也就是说在HTTP这个
级别,协议对于发送过的请求或响应都不做持久化处理。
使用HTTP协议,每当有新的请求发送时,就会有对应的新响应产生。协议本身并不保留之前一切的请求或响应报文的信息。这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把HTTP协议设计成如此简单的。

HTTP/1.1 虽然是无状态协议,但为了实现期望的保持状态功能,于是引入了Cookie技术。有了Cookie再用HTTP协议通信,就可以管理状态了。有关 Cookie 的详细内容稍后讲解。

2. HTTP 版本

HTTP 0.9

HTTP0.9 是第一个版本的HTTP协议,已过时。它的组成极其简单,只允许客户端发送GET这一种请求,且不支持请求头。由于没有协议头,造成了HTTP 0.9协议只支持一种内容,即纯文本。不过网页仍然支持用HTML语言格式化,同时无法插入图片。

HTTP 1.0

HTTP协议的第二个版本,第一个在通讯中指定版本号的HTTP协议版本,至今仍被广泛采用。相对于HTTP 0.9 增加了如下主要特性:
请求与响应支持头域
响应对象以一个响应状态行开始
响应对象不只限于超文本
开始支持客户端通过POST方法向Web服务器提交数据,支持GET、HEAD、POST方法
支持长连接(但默认还是使用短连接),缓存机制,以及身份认证 

HTTP 1.1

HTTP协议的第三个版本是HTTP 1.1,是目前使用最广泛的协议版本 。HTTP 1.1是目前主流的HTTP协议版本,HTTP 1.1引入了许多关键性能优化:keepalive连接,chunked编码传输,字节范围请求,请求流水线等,扩展了HTTP方法,对于http协议的结构和头部重要信息,后面会有章节单独学习。

HTTP/1.0 和 HTTP/1.1 支持的方法


3. TCP报文结构分析

 前面文章提到过:确保可靠性的 TCP 协议,TCP是为了进行连接的确认,保证发送的数据方向(不是数据,而是确保当前发送的请求是正确的方向)不会出错,这里涉及到三次握手和四次挥手,下文中会去介绍。


这里主要介绍几个在下面会涉及到的东西:

Sequence/Acknowledgment number

TCP会话的每一端都包含一个32位(bit)的序列号,该序列号被用来跟踪该端发送的数据量。每一个包中都包含序列号,在接收端则通过确认号用来通知发送端数据成功接收。当某个主机开启一个TCP会话时,他的初始序列号是随机的,可能是0和4,294,967,295之间的任意值,然而,像Wireshark这种工具,通常显示的都是相对序列号/确认号,而不是实际序列号/确认号,相对序列号/确认号是和TCP会话的初始序列号相关联的。这是很方便的,因为比起真实序列号/确认号,跟踪更小的相对序列号/确认号会相对容易一些。

所以这里的Sequence number是序列号,上图中的是一个相对序列号,Acknowledgment number是确认号,上图中也是一个相对确认号。这两个值在三次握手和四次挥手时起到作用,具体的后文回去看。

Flags

标志位表示当前数据包的类型:
SYN: synchronous建立联机
ACK: acknowledgement确认 (只能为1)
PSH: push传送
FIN: finish结束
RST: reset重置
URG: urgent紧急

4. TCP三次握手

如下图是发送http请求的三次握手建立链接,然后我们每一步去看具体发生了什么?


客户端发送SYN建立联机


如图Sequence number为0,Acknowledge number为0。标志位为SYN。这里表明的含义为客户端请求建立联机。
现在客户端的序列号为0(一定要记住,这里为0是可以的,上面我们已经说了序列号的数字范围)。

说明一下Acknowledge number只有在标志位ACK=1的时候才有意义。

服务端确定客户端主机请求建立连接


如图Sequence number为0,Acknowledge number为1。标志位为SYN,ACK。这里表明的含义为服务端确认客户端请求建立联机。

现在服务端的序列号为0(服务器产生的随机序列号码),服务端确认号为1。这里的ack = sequence number + 1,也就是上一个请求建立联机的0+1 = 1.

客户端发送请求建立链接


客户端主机收到后检查ack number是否正确,即第一次发送seq number + 1(也就是0+1 = 1), 如果正确,客户端主机会在发送 seq = 0(第一次请求的seq number) + 1 = 1, ack = 0(服务端返回的seq number) + 1 = 1, ACK = 1,服务端主机会在接受请求后确认seq, ack的值是否正确,如果正确的话,就建立连接。

讲解:TCP三次握手的数值变化



a. 首先客户端主机向服务器主机发送 SYN = 1,随机产生顺序号码seq number = x 的数据包到服务器。
这里的含义是说:首先客户端发送联机请求(注意是联机,不是建立链接),然后发送seq number =x的数值到服务端。这里发送这个数值是为了得到服务端返回值的时候确认是否建立链接。这里的规则是在b中返回的ack number为x+1。

b. 服务器主机收到请求后,通过 syn = 1, 确定客户端主机请求建立连接 ,然后向客户端主机发送SYN = 1 , seq = y(服务器产生的随机随机号码), ack = x+ 1, ACK = 1 。我们注意到这里不仅返回了ack number,也返回了一个seq number,注意这里的seq = y,这里的值为了客户端发送第二次请求的时候(也就是步骤c)服务端再次验证,验证节客户端成功接收到了客户端的请求。

c. 客户端主机收到后检查ack number是否正确,即第一次发送seq number + 1(x + 1), 如果正确,客户端主机会在发送 seq = x + 1, ack = y + 1, ACK = 1.服务端主机会在接受请求后确认seq, ack的值是否正确,如果正确的话,就建立连接。当客户端验证了ack number的值正确(接着a步骤的规则),然后发送ack = y + 1,这里是为什么是seq = x +1, ack = y + 1。因为客户端和服务端序列号的开始值是不一样的。客户端发送seq number其实都是以x为基准在发送,因为这样才能够保证客户端的序列号正常。发送ack则是以服务端发送的序列号为基准,因为这个是用于服务端去验证,所以它的基准就是y了。反之,服务度发送seq numer则是以服务端序列号为基准,发送ack muber则是以客户端为基准。

一句话,不管客户端还是服务端,seq number 都是对应着自己的序列号,ack number则是要发给对方进行验证的,则是以对方序列号为基准。不知道这样说大家能不能理解。(这也是我自己的理解,有疑问可以提出来)。

实例:查看http请求过程中的数值变化


如图:红色框是建立tcp链接,绿色框是发送http请求,蓝色框是断开连接(断开连接下文会去看,这里只是验证序列号的数值变化),然后我们通过wirehshark查看tcp中的数值变化。


我们直接从第四条开始看,也就是发送http请求的地方。我们在途中可以看出len: 573的字段,前面建立链接的时候的客户端的seq number还是1,现在发送请求需要占用573的序列,那我们想一下下一个请求的序列号从哪里开始:当然是客户端当前额序列号1 + tcp len 573 = 574。然后发送seq number = 1(建立链接时服务端的序列号),ack number = 574。

这里你可能会想为什么ack = 574,你想一下客户端发送请求之后,服务端还是要验证当前的序列号是不是正确的,那么服务端这么验证呢?我们推到上一条服务端发送到客户端的请求的值seq number = 1, ack number=1,然后经过现在这一条请求发送了长度为573的tcp片段,那么server就可以根据发送请求的ack = x + 上一次的ack number去进行验证,这里就是ack = 573 + 1 = 574,验证通过。第二个就是这个ack 在经过服务端处理之后在通过服务端发送请求的seq number返回到client,用于client的验证574. 

我们接着看第五条,是服务端返回结果,从图中可以看出是1078长度的tcp片段。r然后服务端发送seq number = 1079,发送1079也就是1078 + 之前服务端的序列号1的结果,同样的这个值也是接线来client在发送请求时,server会对这个值的验证。同事发送ack number = 574给client,client自己会验证成功。

后面断开连接就先不看了,因为后文还要看四次挥手断开连接。

讲解:http请求过程中的数值变化规律


如图:在建立链接之后,服务端和客户端都知道对方当前序列号,所以双方发送的seq number都是对方当前的序列号,ack number则是对方接下来发送请求的序列号。因为双方接受的数据都是由对方发送的长度来决定的。

讲解:为什么需要三次握手建立链接

主要是为了防止已失效的连接请求报文段突然又传到了对方,因而产生错误。为什么呢?假设客户端发送请求到服务端不知什么原因没有达到。但是客户端在发送这个请求之后还会发其他的请求,这个时候的序列号已经发生了变化,然后客户端发现之前的请求没有响应,然后带着新的seq number去发送,然后通过三次链接双方记录了对方的序列号。然后在server 接受客户端请求的时候,发现有两个请求到达,这个时候服务端可以通过当前的序列号进行判断,哪一个是符合自身当前序列号的进行区分,这样就避免了失效的请求。第二方面我认为还是双方进行对方序列号的认知过程。

5. 四次挥手(双方都有可能开始断开连接)


a. 数据传输结束后,主机A向主机B发送释放连接请求。FIN = 1,序号seq就是对方发送下一次请求的序列号,这里因为是断开连接tcp长度为0,所以就是对方的当前序列号加上1(u).
b. 主机B收到释放连接通知后发出确认信息,ack = u +1,这样A到B的连接就释放了,此时的连接处于半关闭状态。因为B还可以向A发送数据。
c. 在数据B向主机A的数据发送结束后,主机B会向主机A发送释放连接请求. FIN =1, ack仍然等于u + 1, 因为这段时间没有A向B发送数据,序号seq等于以传送数据的最后一个字节的序号加1(v).
d. 主机A接受到书记B释放连接请求之后,将ACK = 1, ack = w + 1, seq = u + 1.这样所有的连接都已经关闭,整个连接才算关闭。

讲解:为什么需要四次挥手断开连接?

保证双反都已经没有数据发送。

讲解:四次挥手TIME_WAIT状态需要经过2MSL(最大报文段生存时间)之后close

a. 为了保证A发送的最有一个ACK报文段能够到达B。
b. 为了防止三次握手发生的已失效的请求报文段发生在本次连接中。

6. 持久连接节省通信量

HTTP 协议的初始版本中, 每进行一次 HTTP 通信就要断开一次 TCP连接。

持久连接

为解决上述 TCP 连接的问题, HTTP/1.1 和一部分的 HTTP/1.0 想出了持久连接(HTTP Persistent Connections, 也称为 HTTP keep-alive 或HTTP connection reuse) 的方法。 持久连接的特点是, 只要任意一端没有明确提出断开连接, 则保持TCP连接状态。

在 HTTP/1.1 中,所有的连接默认都是持久连接,但在 HTTP/1.0 内并未标准化。 虽然有一部分服务器通过非标准的手段实现了持久连接,但服务器端不一定能够支持持久连接。 毫无疑问,除了服务器端, 客户端也需要支持持久连接。

管线化

持久连接使得多数请求以管线化(pipelining) 方式发送成为可能。 从前发送请求后需等待并收到响应, 才能发送下一个请求。 管线化技术出现后, 不用等待响应亦可直接发送下一个请求。这也是现在浏览器为什么可以并发多条请求的原因。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值