简介

服务端和客户端应该怎么进行通信呢?我们常见的方法就是客户端向服务器端发送一个请求,然后服务器端向客户端发送返回的响应。这种做法比较简单,逻辑也很清晰,但是在某些情况下,这种操作方式并不好使。

比如在服务器端的某些变动需要通知客户端的情况,因为客户端并不知道服务器端的变动是否完成,所以需要不停的使用轮循去检测服务器的状态。这种做法的缺点就是太过于浪费资源。如果希望及时性好的话,需要不断的减少轮循的时间间隔,导致极大的服务器压力和资源的浪费。

那么有没有好的解决办法呢?

既然不能使用查询,那么就改成服务器推送就行了。我们知道在HTTP/2中,提供了一种服务器推送的方式,但是这种方式是单向的,也就是说在同一个TCP连接之上,并不能实现客户端和服务器端的交互。

于是我们需要一个能够双向交互的网络协议,这个协议就是WebSocket。

webSocket vs HTTP

webSocket是一个基于底层TCP协议的一个双向通信网络协议。这个双向通信是通过一个TCP连接来实现的。webSocket于2011年以RFC 6455发布成为IETF的标准。

同样作为基于TCP协议的标准协议,它和HTTP有什么区别呢?

如果以OSI的七层模型来说,两者都位于七层协议的第四层。但是两者是两种不同的协议。鉴于HTTP已经如此流行了,为了保证webSocket的通用性,webSocket也对HTTP协议进行了兼容。也就是说能够使用HTTP协议的地方也就可以使用webScoket。

这个和之前讨论的HTTP3有点类似,虽然HTTP3是一个新的协议,但是为了保证其广泛的应用基础,HTTP3还是在现有的UDP协议上进行重写和构建。目的就是为了兼容。

实时上,webSocket使用的是HTTP upgrade header,从HTTP协议升级成为webSocket协议。

HTTP upgrade header

什么是HTTP upgrade header呢?

HTTP upgrade header是在HTTP1.1中引入的一个HTTP头。当客户端觉得需要升级HTTP协议的时候,会向服务器端发送一个升级请求,服务器端会做出相应的响应。

对于websocket来说,客户端在和服务器端建立连接之后,会首先发送给服务器端 Upgrade: WebSocket 和 Connection: Upgrade 头。服务器端接收到客户端的请求之后,如果支持webSocket协议,那么会返回同样的Upgrade: WebSocket和Connection: Upgrade 头到客户端。客户端接收到服务器端的响应之后,就知道服务器端支持websocket协议了,然后就可以使用WebSocket协议发送消息了。

websocket的优点

其实前面我们也讲过了,相对于传统的HTTP拉取,webSocket可以借助于一个TCP连接实现数据的实时传输。可以在减少服务器压力的同时,实现服务器和客户端的实时通信。

webScoket的应用

WebSocket使用的是ws和wss作为URI的标记符。其中ws表示的是websocket,而wss表示的是WebSocket Secure。

因为通常来说我们使用的web浏览器来和服务器进行通信。浏览器就是我们的web客户端,对于现代浏览器来说,基本上都支持WebSocket协议,所以大家可以放心应用,不用担心协议兼容的问题。

对于浏览器客户端来说,可以使用标准的浏览器WebSocket对象,来和服务器进行通信,我们看一个简单的javascript客户端使用webSocket进行通信的例子:

// 使用标准的WebSocket API创建一个socket连接
const socket = new WebSocket('ws://www.flydean.com:8000/webscoket'); // 监听webSocket的open事件
socket.onopen = function () {
setInterval(function() {
if (socket.bufferedAmount == 0)
socket.send(getUpdateData());
}, 50);
}; // 监听接收消息事件
socket.onmessage = function(event) {
handleUpdateData(event.data);
}; // 监听socket关闭事件
socket.onclose = function(event) {
onSocketClose(event);
}; // 监听error事件
socket.onerror = function(event) {
onSocketError(event);
};

上述代码主要就是各种监听socket的事件,然后进行处理,非常简单。

websocket的握手流程

上面我们讲过了,websocket是从HTTP协议升级的,客户端通过发送:

Upgrade: websocket
Connection: Upgrade

到服务器端,对协议进行升级。我们举一个具体的例子:

GET /webscoket HTTP/1.1
Host: www.flydean.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x123455688xafe=
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://flydean.com

对应的server端的返回:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: Qhfsfew12445m=
Sec-WebSocket-Protocol: chat

在上面的例子中,除了使用Upgrade头之外,客户端还向服务器端发送了Sec-WebSocket-Key header。这个header包含的是一个 base64 编码的随机字节。server对应的会返回这个key的hash值,并将其设置在Sec-WebSocket-Accept header中。

这里并不是为了安全操作,而是为了避免上一次的连接缓存情况。

WebSocket API

要想在浏览器端使用WebSocket,那么就需要用到客户端API,而客户端API中最主要的就是WebSocket。

它提供了对websocket的功能封装。它的构造函数是这样的:

WebSocket(url[, protocols])

url就是要连接的websocket的地址,那么可选的protocols是什么呢?protocols可以传入单个协议字符串或者是协议字符串数组。它指的是 WebSocket 服务器实现的子协议。

子协议是在WebSocket协议基础上发展出来的协议,主要用于具体的场景的处理,它是是在WebSocket协议之上,建立的更加严格的规范。

比如,客户端请求服务器时候,会将对应的协议放在Sec-WebSocket-Protocol头中:

GET /socket HTTP/1.1
...
Sec-WebSocket-Protocol: soap, wamp

服务器端会根据支持的类型,做对应的返回,如:

Sec-WebSocket-Protocol: soap

WebSocket API有四种状态,分别是:

状态定义 取值
WebSocket.CONNECTING 0
WebSocket.OPEN 1
WebSocket.CLOSING 2
WebSocket.CLOSED 3

通过调用close或者Send方法,会触发相应的events事件,WebSocket API 的事件主要有:close,error,message,open这4种。

下面是一个具体使用的例子:

// 创建连接
const socket = new WebSocket('ws://localhost:8000'); // 开启连接
socket.addEventListener('open', function (event) {
socket.send('没错,开启了!');
}); // 监听消息
socket.addEventListener('message', function (event) {
console.log('监听到服务器的消息 ', event.data);
});

总结

以上就是websocket的简单介绍和使用,有想知道Websocket到底是怎么进行消息传输的,敬请期待我的下一篇文章。

本文已收录于 http://www.flydean.com/06-websocket/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

小学生都能读懂的网络协议之:WebSocket的更多相关文章

  1. 快速读懂 HTTP/3 协议

    在 深入浅出:HTTP/2 一文中详细介绍了 HTTP/2 新的特性,比如头部压缩.二进制分帧.虚拟的"流"与多路复用,性能方面比 HTTP/1 有了很大的提升.与所有性能优化过程 ...

  2. 小学生都能看懂的FFT!!!

    小学生都能看懂的FFT!!! 前言 在创新实践重心偷偷看了一天FFT资料后,我终于看懂了一点.为了给大家提供一份简单易懂的学习资料,同时也方便自己以后复习,我决定动手写这份学习笔记. 食用指南: 本篇 ...

  3. 一文读懂网管协议 - SNMP,NETCONF,RESTCONF

    本文篇幅较长,主要涉及以下内容: 介绍传统 CLI 配置网络设备存在的挑战,网管协议出现的背景 SNMP 原理,交互过程,以及 trade-off NETCONF 架构,交互过程 RESTCONF 架 ...

  4. 小学生都看得懂的C语言入门(1): 基础/判别/循环

    c基础入门, 小学生也可以都看得懂!!!! 安装一个编译器, 这方面我不太懂, 安装了DEV-C++  ,体积不大,30M左右吧, 感觉挺好用,初学者够了. 介绍下DEV 的快键键: 恢复 Ctrl+ ...

  5. 网络协议之:WebSocket的消息格式

    目录 简介 WebSocket的握手流程 webSocket的消息格式 Extensions和Subprotocols 总结 简介 我们知道WebSocket是建立在TCP协议基础上的一种网络协议,用 ...

  6. 译《The Part-Time Parliament》——终于读懂了Paxos协议!

    最近的考古发现表明,在Paxos小岛上,尽管兼职议会成员都有逍遥癖,但议会模式仍然起作用.他们依旧保持了一致的会议记录,尽管他们频繁的进出会议室并且他们的信使还很健忘.Paxon议会协议提供了一种新方 ...

  7. 小学生都看得懂的C语言入门(6): 字符串

    1.字符用 char 表示 #include<stdio.h> int main() { char c; char d; c=; d='; if (c==d){ printf(" ...

  8. 小学生都能看懂的数位dp

    前言 数位dp其实很久前就知道了,也做过几道和其他算法混在一起的题目,其实通过手玩是能做的 但毕竟是种算法,还是系统学下比较好(节省手玩时间) 模板题 P2602 [ZJOI2010]数字计数 化简题 ...

  9. 这是一篇每个人都能读懂的最小生成树文章(Kruskal)

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是算法和数据结构专题的第19篇文章,我们一起来看看最小生成树. 我们先不讲算法的原理,也不讲一些七七八八的概念,因为对于初学者来说,看到 ...

随机推荐

  1. python3+telnetlib实现简单自动测试

    1 telnetlib介绍 1.1 简介 官方介绍文档:telnetlib -- Telnet 客户端 - Python 3.9.6 文档 telnetlib 模块提供一个实现Telnet协议的类 T ...

  2. miniFTP项目实战三

    项目简介: 在Linux环境下用C语言开发的Vsftpd的简化版本,拥有部分Vsftpd功能和相同的FTP协议,系统的主要架构采用多进程模型,每当有一个新的客户连接到达,主进程就会派生出一个ftp服务 ...

  3. SIM900A—发送、接收中英文短信

    文章目录 一.SMS简介 二.短信的控制模式与编码 1.Text Mode 2.PDU Mode 3.GSM编码 4.UCS2编码 三.收发英文短信 1.AT+CPMS查询短信数量 2.AT+CNMI ...

  4. (四)Linux之用户管理(用户和用户组)

    Linux之用户管理(用户和用户组) 目录 Linux之用户管理(用户和用户组) 一.概述 二.用户和组的关系 三.关于UID和GID(用户ID和组ID) 四.用户和组的数据 /etc/passwd内 ...

  5. 备战秋招之十大排序——O(n)级排序算法

    时间复杂度O(n)级排序算法 九.计数排序 前文说到,19591959 年 77 月,希尔排序通过交换非相邻元素,打破了 O(n^2)的魔咒,使得排序算法的时间复杂度降到了 O(nlog n) 级,此 ...

  6. [1.1W字] 复习: CSS 9个背景属性&6种渐变函数, 学会可以手写实现AI中强大的"任意渐变"! #Archives009

    Title/ CSS Background&Gradient完全指南 #Archives009 序: 关于 background 属性, 了解点CSS的人总会知道个大概. 但是你肯定多半还有点 ...

  7. npm常用命令及其node相关工具汇总

    它是一个事件驱动异步I/O单进程的服务端JS环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好. 浏览器是JS的前端运行环境. Node.js是JS的后端运行环 ...

  8. 深入浅出Mybatis系列(五)---配置详解之settings设置

    settings 中的设置是非常关键的,它们会改变 MyBatis 的运行时行为.下表描述了设置中各项的意图.默认值等. 设置参数 描述 有效值 默认值 cacheEnabled 该配置影响的所有映射 ...

  9. Linux命令:ps -ef |grep java

    一.ps -ef |grep java 查看包含"java"的所有进程 二.涉及命令详解 ps命令将某个进程显示出来(是LINUX下最常用的也是非常强大的进程查看命令) grep命 ...

  10. Object--Date--calendar--System--StringBuilder--基本数据类型包装类型

    Object java.lang.Object类是Java语言中的根类,即所有类的父类 默认toString()方法打印的是对象在堆中的地址值 默认equals()方法比较的也是地址(String中对 ...