websocket学习
//理论部分转载自:https://www.jianshu.com/p/95d259b05c67
谈到Web实时推送,就不得不说WebSocket。谈到Web实时推送,就不得不说WebSocket。Comet又可细分为两种实现方式,一种是长轮询机制,一种称为流技术,这两种方式实际上是对轮询技术的改进,这些方案带来很明显的缺点,需要由浏览器对服务器发出HTTP request,,大量消耗服务器带宽和资源。
面对这种状况,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽并实现真正意义上的实时推送。
1. wbesocket是什么?
WebSocket是HTML5出的东西(协议)
可以把 WebSocket 看成是 HTTP 协议为了支持长连接所打的一个大补丁,它和 HTTP 有一些共性,是为了解决 HTTP 本身无法解决的某些问题而做出的一个改良设计。WebSocket不是HTTP协议,HTTP只负责建立WebSocket连接。
- WebSocket协议本质上是一个基于TCP的 独立的协议,能够在浏览器和服务器之间建立双向连接,以基于事件的方式,赋予浏览器实时通信能力。
- 协议名为"ws",这意味着一个websocket连接地址会是这样的写法:ws://**。websocket协议本质上是一个基于tcp的协议
- 是服务器实现的。客户端通过html5与服务器交互。http是不持续连接的,而websocket是。必须服务器支持websocket协议,才有效。对于不支持websocket服务的服务器,你客户端怎么写代码都没用。
WebSocket实战:
Web领域的实时推送技术,这种技术要达到的目的是让用户不需要刷新浏览器就可以获得实时更新。它有着广泛的应用场景,比如双人对战小游戏、在线聊天室、在线客服系统、评论系统、WebIM等。
2.websocket解决了什么问题?
在了解这个之前我先来科普一下:
了解背景:
在以前 HTTP 协议中所谓的 **keep-alive connection** 是:
指在一次 TCP 连接中完成多个 HTTP 请求,但是对每个请求仍然要单独发 header;
所谓的 polling :
是指从客户端(一般就是浏览器)不断主动的向服务器发 HTTP 请求查询是否有新数据 。
这两种模式有一个共同的缺点:
就是除了真正的数据部分外,服务器和客户端还要大量交换 HTTP header,信息交换效率很低。
它们建立的“长连接”都是伪.长连接.
只不过好处是不需要对现有的 HTTP server 和浏览器架构做修改就能实现。
http long poll,或者ajax轮询都可以实现实时信息传递
ajax轮询
原理:让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。
- 客户端(发请求,建立链接):啦啦啦,有没有新信息(Request)
- 服务端:没有(Response)
- 客户端(发请求,建立链接):啦啦啦,有没有新信息(Request)
- 服务端:没有。。(Response)
- 客户端(发请求,建立链接):啦啦啦,有没有新信息(Request)
- 服务端:你好烦啊,没有啊。。(Response)
- 客户端(发请求,建立链接):啦啦啦,有没有新消息(Request)
- 服务端:好啦好啦,有啦给你。(Response)
- 客户端(发请求,建立链接):啦啦啦,有没有新消息(Request)
http long poll:
- 客户端(发请求,建立链接):啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request)等等等。。。。。
- 服务端:额。。 等待到有消息的时候。。来 给你(Response)
- 客户端(发请求,建立链接):啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request) -loop
从上面可以看出其实这两种方式,都是在不断地建立HTTP连接,然后等待服务端处理,可以体现HTTP协议的另外一个特点,被动性(服务端不能主动联系客户端,只能有客户端发起。)。
由此可以看出上面那种方式的缺陷:
非常消耗资源的:
ajax轮询 需要服务器有很快的处理速度和资源。(速度)
long poll 需要有很高的并发,也就是说同时接待客户的能力。(场地大小)
所以在这种情况下出现了,Websocket出现了。
3、websocket建立持久连接的原理
通过第一个 HTTP request 建立了 TCP 连接之后,之后的交换数据都不需要再发 HTTP request了,使得这个长连接变成了一个真.长连接。但是不需要发送 HTTP header就能交换数据显然和原有的 HTTP 协议是有区>别的,所以它需要对服务器和客户端都进行升级才能实现。
在此基础上 WebSocket 还是一个双通道的连接,在同一个 TCP 连接上既可以发也可以收信息。此外还有 multiplexing 功能,几个不同的 URI 可以复用同一个 WebSocket 连接。这些都是原来的 HTTP 不能做到的。
那为什么它会解决服务器上消耗资源的问题呢?
- 建立持久连接
- 只需要一次握手
- 服务器主动推送消息
4、websocket应用
客户端
一旦取得 Web 服务器上的 Web Socket 连接之后,就可以通过调用 send() 方法从浏览器发送数据到服务器上,通过onmessage 事件处理程序从服务器接收数据到浏览器中。
下面是创建一个新的 WebSocket 对象的 API。
var Socket = new WebSocket(url, [protocal] );
WebSocket 事件:
假定我们已经创建了上述的 Socket 对象,客户端通过websocket API提供的如下4个事件进行编程
事件 | 事件处理程序 | 描述 |
---|---|---|
open | Socket.onopen | 建立 socket 连接时触发这个事件。 |
message | Socket.onmessage | 客户端从服务器接收数据时触发。 |
error | Socket.onerror | 连接发生错误时触发。 |
close | Socket.onclose | 连接被关闭时触发。 |
<html> <head> <title>ws demo</title> <meta charset="utf8"> </head> <body> <script> var ws = new WebSocket('ws://localhost:8080'); //建立连接成功时触发 ws.onopen = function () { console.log('client: ws connection is open'); ws.send('hello'); }; //客户端从服务器接收数据时触发 ws.onmessage = function (e) { console.log('client: received %s', e.data); }; </script> <p>test</p> </html>
服务端
WebSocket 在服务端的实现非常丰富。Node.js、Java、C++、Python 等多种语言都有自己的解决方案。
这里服务端用了ws
这个库。相比大家熟悉的socket.io
,ws
实现更轻量,更适合学习的目的。
代码如下,监听8080端口。当有新的连接请求到达时,打印日志,同时向客户端发送消息。当收到到来自客户端的消息时,同样打印日志。
index.js
var app = require('express')();
var server = require('http').Server(app);
var WebSocket = require('ws');
var wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
console.log('server: receive connection.');
ws.on('message', function incoming(message) {
console.log('server: received %s', message);
ws.send('server: reply');
});
ws.send('world');
});
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
app.listen(3000);
运行 node index.js
,查看 http://localhost:3000/
抓包观察,可发现其在TCP之上,属于应用层:
参考链接:
1. https://www.jianshu.com/p/95d259b05c67
2. https://www.cnblogs.com/chyingp/p/websocket-deep-in.html
3. https://juejin.im/entry/5bea2106e51d45053d5c4fc3