第一次看到 ws://wss:// 时候,感觉好高级啊,还有这种协议。

Websocket 历史

WebSocket是在2008年6月诞生的1。经由IEFT标准化后,2009年chrome 4第一个提供了该标准支持,并默认启用。于2011年由IEFT标准化为RFC 6455

现在的浏览器均已支持该标准。

Websocket 出现的背景

思考一下我们经常遇到的一种需求场景,要求在某个网页下,网页的内容可以实时更新。

这种情况下,最大众化的方式就是轮询接口了,即通过定时器,定时请求接口,获取到最新的信息后,将内容更新到页面中,如下:

setInterval(() => {
 queryAPI().then(() => update());
}, 1000);

但是我们知道,这种定时器的延时并不是很精确,而且加上接口的请求时延,实际时间可能不止代码中所预先设定的时间长度,所以这种实时更新是伪实时更新。

除此之外,还有一点可能会经常遇到,即,我们更新信息并总是要更新整个页面上所有可以看到的信息,我们更关注一些经常变化的信息,比如状态,状态的信息可能大小只有几个字节,但是我们轮询接口拿到的信息却是这个页面的所有信息,大小自然不只几个字节,但是除状态以外的信息都可以视作是冗余的。

我们实际只需要一个字段,而且即使后端提供只返回状态的接口,但实际在一个请求中还要计算ip报文头的大小,依旧是很占用带宽的。

轮询这种解决方案目前依旧是非常流行,最新的轮询技术是Comet,这种技术虽然可以实现双向通信,但仍然需要反复发出请求。而且在Comet中普遍采用的HTTP长连接也会消耗服务器资源2。

Websocket通信模式

了解网络的都知道,数据传输分为单工、半双工、全双工三种工作模式。

Websocket是基于TCP的,使用全双工通信模式的协议,他使得客户端和服务端之间的数据交换变得更简单。而且,作为一个工作在全双工模式下的协议,服务端可以在建立连接后随时向客户端推送消息。

由于协议是基于TCP的,所以websocket也是需要建连和关闭连接的,但要注意的是,一般在websocket的握手通常指的是:客户端发送一个http请求到服务端,服务端响应后标志这个链接建立起来。而不是指tcp的三次握手。

另外在RFC 6455 1.1节「Background」中介绍:WebSocket通过HTTP端口的80和443进行工作,并支持HTTP代理和中介。

原文:it is designed to work over HTTP ports 80 and 443 as well as to support HTTP proxies and intermediaries

为了实现和HTTP的兼容性,WebSocket握手使用HTTP的Upgrade头将HTTP协议转换成Websocket协议。

作为一种协议,websocket自然也是有其用于协议控制的头部信息的,但是相对于HTTP请求每次都要带上完整的头部信息,传输数据时,websocket数据包的头部信息就相对较小,从而降低了控制开销。

相对于前文所提到的轮询接口,websocket可以做到服务端直接向客户端传输数据,省去了客户端发起请求的步骤,同时没有间隔时间,只要服务端内容变化,就可以告知客户端,实时性上有了很大的提高。

Websocket 使用

WebSocket使用十分简单,只需要关注以下API:

  1. WebSocket(url[, protocol]) 构造函数

使用 new WebSocket(xxx) 创建对象时,会同时建立与服务器的连接

  1. WebSocket.onopen , WebSocket.onclose

分别对应连接成功、失败时的回调,这里可以做一些初始化、销毁的工作

  1. WebSocket.onmessage

实际处理数据是用的该函数

在数据处理完成后,需要移除回调函数,不然可能会影响到其他地方的处理

const ws = new WebSocket('ws://sdf.com');
function handleData(evt) {
 // handle server data.
}
ws.onmessage = handleData;
ws.addEventListener('message', handleData);
  1. WebSocket.send

主动向服务端发送消息,可以通过send和onmessage进行数据互动,如:

ws.send('list');

ws.onmessage = evt => {
 const data = evt.data;
 if (data === 'hello') {
   console.log('world');
   return ;
}
 try {
const obj = JSON.parse(data);
   switch (obj.type) {
     case 'list':
       // do something.
  }
} catch (ex) {}
}
  1. WebSocket.close

关闭连接

Node服务端的实现,这个就参考相关的库吧,比较复杂。

衍生知识

http协议至今,主要经历了三个版本。

  • http1.0 短连接,单工通信

    • http/1.0默认的模型是短连接,每个HTTP请求都由他自己独立完成,下图左1,可以看到每一个http请求都对应了一个建立连接关闭连接的阶段,每一个请求都有TCP握手和挥手的阶段。
    • 在这个模型下,想要做到实时更新页面数据,只能考虑轮询。
  • http1.1 支持长链接,半双工通信

    • 1.0之后的版本,1.1会让某个连接保持一定的时间,在这段时间里重复发送一系列请求(下图左2),就是保活。
  • http2.0 支持多路复用,全双工通信

参考文献

[1]  [whatwg] TCPConnection feedback

[2]  wiki

[3]  RFC 6455

[4]  Websocket教程

[5]  HTTP1.x连接管理

浅浅的聊一下 WebSocket的更多相关文章

  1. websocket 实现单聊群聊 以及 握手原理+加密方式

    WebSocket 开始代码 服务端 群聊 # type:WebSocket 给变量标注类型 # websocket web + socket from geventwebsocket.server ...

  2. websocket实现简单聊天程序

    程序的流程图: 主要代码: 服务端 app.js 先加载所需要的通信模块: var express = require('express'); var app = express(); var htt ...

  3. Python Web学习笔记之WebSocket 通信过程与实现

    一.什么是 WebSocket ? WebSocket 是一种标准协议,用于在客户端和服务端之间进行双向数据传输.但它跟 HTTP 没什么关系,它是基于 TCP 的一种独立实现. 以前客户端想知道服务 ...

  4. websocket和通信

    最近默默的在学websocket,推荐的当然是阮一峰的博客了,其中也学到了不少  可以去看看咯 http://www.ruanyifeng.com/blog/2017/05/websocket.htm ...

  5. [技术选型] Node.js

    Nodejs标准的web开发框架Express,可以帮助我们迅速建立web站点,比起PHP的开发效率更高,而且学习曲线更低.非常适合小型网站,个性化网站 NodeJS适合运用在高并发.I/O密集.少量 ...

  6. 巨蟒python全栈开发flask5

    1.轮询&&长轮询&&长连接 2.GeventWebsocket 3.Websocket群聊 4.Websocket单聊 5.websocket握手 6.websock ...

  7. 一例完整的websocket实现群聊demo

    前言 业余我都会花一些时间在tcp.http和websocket等领域的学习,现在觉得有点收获,所以把一个基于websocket的群聊功能的例子提供给大家玩玩.当然这是一个很完整的例子,包括webso ...

  8. websocket(二)--简单实现网页版群聊

    websocket可以实现服务端的消息推送,而不必在客户端轮询,大大的节省的资源,对于实时通讯来说简直是个大喜讯. 在上一篇文章中介绍了协议握手,这篇文章将通过实现简单的群聊来帮助进一步了解webso ...

  9. 补习系列(20)-大话 WebSocket 与 "尬聊"的实现

    目录 一.聊聊 WebSocket 二.Stomp 是个什么鬼 三.SpringBoot 整合 WebSocket A. 引入依赖 B. WebSocket 配置 C. 控制器 D. 前端实现 四.参 ...

随机推荐

  1. nginx入门教程 (转)

    1.Nginx 状态码配置和错误文件 server { # 配置访问 /test.js 时报 403 错 location /test.js { return 403; } # 配置访问 /404 时 ...

  2. HTML页元素自适应+居中总结(不定期补充)

    感谢大佬:https://www.cnblogs.com/SallyShan/p/11480685.html 图片自适应 背景图片自适应 /*背景页*/ #page_content{ width: 1 ...

  3. PHP中常见的数字掐头去尾操作方法

    四舍五入round round( float $val[, int $precision = 0[, int $mode = PHP_ROUND_HALF_UP]] ) : float 对浮点数进行四 ...

  4. Windows 7 Ubuntu 修改系统启动加载项

    由于现在硬盘越来越大,越来越廉价.所以越来越多的很为了方便工作学习,在一台物理机上安装多个操作系统. 下面我们就来介绍安装多个操作系统后,每次开机后,到底默认引导哪个系统,由谁说的算? 由引导项说的算 ...

  5. iOS测试模板

    测试模板,每次写一个功能测试Demo时总是要新建一个工程,导入一些第三方库,比较麻烦,先提供一个测试模板,提供一些常用第三方库,自己就不用导了 使用Cocospod管理第三方库 常用(其他自行添加) ...

  6. 《Effective Python》笔记——第2章 函数

    一.函数出错的时候抛异常,而不要返回None pass 二.闭包 书里的例子不好,参考https://www.cnblogs.com/Lin-Yi/p/7305364.html 在一个外函数中定义了一 ...

  7. C语言strtok_s函数

    strtok_s 在C语言中的作用是分割出一个字符串中的单词 在MSDN上参数表: strtok_s strToken String containing token or tokens. strDe ...

  8. 模块和包—Day28

    一.模块 模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. import的过程:import一个模块的时候,首先创建一个属于my_module的内存空间,加载my_ ...

  9. .Net Core AOP之IResultFilter

    一.简介 在.net core 中Filter分为以下六大类: 1.AuthorizeAttribute(权限验证) 2.IResourceFilter(资源缓存) 3.IActionFilter(执 ...

  10. Go Exec 僵尸与孤儿进程

    原文地址:Go Exec 僵尸与孤儿进程 最近,使用 golang 去管理本地应用的生命周期,期间有几个有趣的点,今天就一起看下. 场景一 我们来看看下面两个脚本会产生什么问题: 创建两个 shell ...