一文详解 Websocket 的前世今生
一、阅前热身
什么是 keep-alive
1、keep-alive 只是客户端的一种建议
我们打开百度首页,进一步查看 header。
如图,我们看到请求 header 中有一行:
Connection:keep-alive
keep-alive 是通知服务器,在这个 HTTP Request/Responset 结束后,不要立即断开 TCP 连接(注意是TCP连接,和HTTP没有关系),后面的HTTP Request仍然可以通过这个TCP连接继续传送。
但是!这只是个建议,服务器可能不支持,也可能忽略掉这个建议。也可能因为时间太久而直接断开TCP连接
通俗点解释就是:keep-alive只是通知服务器,您先别挂,一会儿可能还有活儿,至于它挂不挂还是看它心情。
所以,keep-alive只是客户端建议的一种复用TCP连接的方式,至于服务器支持不支持,就由不得客户端了。
2、keep-alive 只是 http 协议中的一部分
keep-alive 是 http 协议中的一部分,也即客户端可以主动的发起 request 到服务器,服务器只能被动的 response 给客户端。
我要想实现服务器主动的push消息给客户端,keep-alive是无能无力的。
二、服务器的消息如何发给客户端
long long ago~ 服务器端要想主动的push消息给客户端(比如网页聊天室消息的即时收发),这是不可能滴。
但是,我可以使用ajax轮询、long poll 技术造一个服务端给客户端主动push消息的假象。
什么是 ajax 轮询?
ajax轮询的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。
场景再现:
客户端:啦啦啦,有没有新信息(Request)
服务端:没有(Response)
客户端:啦啦啦,有没有新信息(Request)
服务端:没有。。(Response)
客户端:啦啦啦,有没有新信息(Request)
服务端:你好烦啊,没有啊。。(Response)
客户端:啦啦啦,有没有新消息(Request)
服务端:好啦好啦,有啦给你。(Response)
客户端:啦啦啦,有没有新消息(Request)
服务端:。。。。。没。。。。没。。。没有(Response) ---- loop
但是这样,有没有发现,大大增加了服务端的负载,并且速度还慢。
什么是 long poll?
long poll和ajax差不多,原理都是采用轮询的方式。只不过long poll是采取的阻塞的方式去轮询。
也即客户端发起一个请求连接,这个连接会阻塞住,直到服务端有了消息,才会response给客户端。
场景再现:
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request)
服务端:额。。等待到有消息的时候。。来 给你(Response)
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request) -loop
long pull 虽然降低了服务器的负载,但是需要服务器有很高的并发能力才可以。
而目前处理高并发的模型基本都是异步非阻塞的模型(比如nginx)。
既想阻塞,又想高并发,几乎不可能。
总结
ajax轮询、long poll技术虽然都能实现服务端消息的实时通知,但是各有缺点,都不是根本的解决办法。
计算机界急需一种新的技术去处理这些需求~
三、Websocket 来啦
既然 ajax 轮询、long poll 都不怎么样。我们发明一种新的协议吧!
Websocket 协议解决了服务器与客户端全双工通信的问题。
注:什么是单工、半双工、全工通信?信息只能单向传送为单工;信息能双向传送但不能同时双向传送称为半双工;信息能够同时双向传送则称为全双工。
websocket协议解析
Websocket 协议包含两部分:一部分是“握手”,一部分是“数据传输”。为了便于演示,我们采用swoole建立一个websocket服务器来演示。
1、握手
① 客户端向服务端发起连接请求
如图,我们在请求服务器的时候,发送了这样的request header。
下面我们就一些比较重要的字段信息进行说明:
Connection:Upgrade #通知服务器协议升级
Upgrade:websocket #协议升级为websocket协议
Host:0.0.0.0:9501 #升级协议的服务主机:端口地址
Sec-WebSocket-Key:K8o1cNIxO2pR6inTIDBSgg== #传输给服务器的key
Sec-WebSocket-Version:13 #websocket协议版本13
Sec-WebSocket-Key有什么用呢?
客户端将这个key发送给服务器,服务器将这个key进行处理,将处理后的key返回给客户端,客户端根据这个key是否正确来判断是否建立连接。
②:服务端返回握手应答
如图,我们看到websocket协议状态码是101.
101表示协议切换成功。
我们查看 websocket 的 response header。如图:
下面解释下reponse header字段的含义
Connection:Upgrade #协议升级成功
Sec-WebSocket-Accept:GnoYH/ip/ZMh+a5rX5P/YR6e68g= #服务端处理之后的key
Sec-WebSocket-Version:13#websocket 协议版本号
Upgrade:websocket#协议升级为websocket
至此,websocket握手成功!下面就尽情的传输数据吧!
2、数据传输
数据传输需要客户端,没什么好说的了。
- Chrome/Firefox/高版本IE/Safari等浏览器内置了JS语言的WebSocket客户端
- 可以使用一些扩展来实现websocket客户端,如php的swoole、workerman。
注意:非WebSocket客户端不能与WebSocket服务器通信
作者:子路 链接:https://juejin.im/post/6844903472278536206
- CentOS6.8_Spark单机部署
- 3.2 Spark调度机制
- 正则表达式中零宽断言的用法
- Spark ReadmeApache Spark
- Apache Spark快速入门
- YARN & Mesos,论集群资源管理所面临的挑战
- Requests库作者Kenneth Reitz的另一神作!虚拟环境及包管理工具Pipenv!
- 你写的单例真的对吗
- TensorFlow layers模块用法
- Spark算子详解及案例分析(分类助记)
- Spark详解07广播变量BroadcastBroadcast
- TensorFlow验证码识别
- python selenium2 开发环境搭建
- 聊聊同步辅助类CountDownLatch
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法