Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Http持久连接及其现代方法 #27

Open
Genluo opened this issue Aug 31, 2019 · 0 comments
Open

Http持久连接及其现代方法 #27

Genluo opened this issue Aug 31, 2019 · 0 comments

Comments

@Genluo
Copy link
Owner

Genluo commented Aug 31, 2019

Http如何实现长连接

首先我们知道Http是一种应用层协议,但是长连接是网络中的一种状态,而实现它需要在传输层进行开发,因为他是基于对真实数据的收发,需要在底层进行管控,那么http作为应用层协议如何能实现“长连接”。

Http长连接和TCP的长连接

真实答案就是Http作为应用层协议,其实他的生命周期在服务器返回结果的时候就结束了,而所谓的支持长连接,其实基于Http请求头部的“keep-alive”的约定,从而向下进行长连接发起的一种约束,该长连接依然是TCP的,所以是TCP协议的长连接

长连接带来的好处

长连接是保持着TCP连接通道,实现http在同一个TCP通道上进行复用,这样的话就能减少TCP三次握手四次挥手每次带来的性能损耗,提高网路利用效率。

0_1324729533QJ15

TCP Keep Alive 与 HTTP Keep Alive 的关系

TCP Keep Alive 和 HTTP Keep Alive 是两个目的不同的技术,不存在谁依赖于谁的关系。TCP Keep Alive 用于探测对端是否存在,而 HTTP Keep Alive 用于协商以复用 TCP 连接。即便一个 TCP 连接未启用 Keep Alive 功能,也不妨碍 HTTP 层面开启长连接。TCP中的keep-alive是一种保鲜装置,当TCP请求响应结束以后,经过TCP_keep_alive_time时间的等待,服务器会发出一个TCP监测包,来看看当前TCP连接是否有效,是否服务器出了问题,如果出现了问题,那么服务器会选择关闭这个连接。如果此时使用的Http的keep alive的长连接协议,这样的话,那么会重新建立新的TCP连接,不影响Http连接

TCP的心跳机制

随着互联网的发展,出现了使用长连接来实现的服务器端推送的要求,但是目前我们知道这种实现存在一个问题,就是客户端如何知道服务端的状态,为了保证服务器和客户端一直保持连接,并且让客户端知道目前的连接状态,存在一种方法就是心跳机制,首先客户端会发送一个心跳包到服务器,服务器在ASK,通过这种方式判断目前的连接状态,如果断了,则会通知上层应用并关闭连接,另外发送心跳包也是避免一段时间没有通信(TCP层面上),NAT超时,NAT表被刷新,导致连接失效,注意这种心跳机制是建立在TCP机制上,和HTTP没有任何关系,Http层面上不能直达此条TCP的连接状态

如何实现服务器端推送技术(消息推送)

随着网络发展和需求的不断变化,有这样一种需求,需要实现服务器端向客户端的主动推动,当时有两种实现思路,一种是采用轮询方式,另一种是通过长轮询的方式实现,但是后面出现了其他的实现,一种是通过

轮询

客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接。

  • 优点:
    • 后端编写比较简单
  • 缺点:
    • 请求中大多数是无用信息,浪费带宽和服务器资源
长轮询(Comet)

客户端向服务器发送Ajax请求,服务器接到请求后hold住连接(注意超时),直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求

  • 优点
    • 在无消息的时候不会频繁的请求,不浪费带宽和服务器资源
    • 可以实现服务器端主动推动,消息及时
  • 缺点
    • 服务器Hold连接会消耗资源
websocket

HTML5开始提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议,它基于TCP传输协议,并复用HTTP建立的TCP连接

1、如何建立连接

首先建立Http连接,复用Http连接听通道升级为websocket协议(只支持Get请求),客户端报文如下:

GET / HTTP/1.1
Host: localhost:8080
Origin: http://127.0.0.1:3000
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: w4v7O6xFTi36lq3RNcgctw==

服务端收到客户端的报文之后返回如下:

HTTP/1.1 101 Switching Protocols
Connection:Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: Oy4NRAQ13jhfONC7bP8dTKb4PTU=

服务器端Sec-WebSocket-Accept是根据客户端的Sec-WebSocket-Key计算得到的,

2、如何交换数据

一旦WebSocket的客户端和服务器端建立连接之后,后续的操作都是基于数据帧的传递,

3、 数据帧格式

涉及到网络深层次的报文格式,因为WebSocket一种比较新的格式,所以需要我们自己手动处理一些情况,推荐使用WS库的方式实现,或者使用node中socket.io实现,这个兼容性比较好,对应不支持websocket的浏览器降级成comet/ajax轮询来实现

4、如何维持连接

采用常见的心跳机制,比如ping-pang来判断两者是否还在连接

5、Sec-WebSocket-Accept

  • 避免服务端收到非法的websocket连接(比如http客户端不小心请求连接websocket服务,此时服务端可以直接拒绝连接)

  • 确保服务端理解websocket连接。因为ws握手阶段采用的是http协议,因此可能ws连接是被一个http服务器处理并返回的,此时客户端可以通过Sec-WebSocket-Key来确保服务端认识ws协议。(并非百分百保险,比如总是存在那么些无聊的http服务器,光处理Sec-WebSocket-Key,但并没有实现ws协议。。。)

  • 用浏览器里发起ajax请求,设置header时,Sec-WebSocket-Key以及其他相关的header是被禁止的。这样可以避免客户端发送ajax请求时,意外请求协议升级(websocket upgrade)

  • 可以防止反向代理(不理解ws协议)返回错误的数据。比如反向代理前后收到两次ws连接的升级请求,反向代理把第一次请求的返回给cache住,然后第二次请求到来时直接把cache住的请求给返回(无意义的返回)。

  • Sec-WebSocket-Key主要目的并不是确保数据的安全性,因为Sec-WebSocket-Key、Sec-WebSocket-Accept的转换计算公式是公开的,而且非常简单,最主要的作用是预防一些常见的意外情况(非故意的)

参考资料

  • [webSocket介绍](
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant