【JS】websocket原理

1.HTTP

HTTP是超文本传输协议,英文写作HyperText Transfer Protocol,它是构建在TCP协议之上的。
在http的两端分别是客户端和服务器,这就是经典的B/S模式。另外,这里的B,就是浏览器的意思,浏览器成为了http的代理,用户的行为将会通过浏览器转化为http请求报文,发送给服务器,服务器也就是S,会处理请求,然后发送响应报文给代理,也就是浏览器,浏览器解析响应报文后,将用户界面展示给用户。这里我们看到,基于http或者https的B/S模式中国,浏览器只负责发送报文、接收报文、解析报文、展示界面,服务器负责处理http请求和发送http响应。

TCP全称为传输控制协议,在OSI模型上属于传输层协议。

七层协议示意图如下:

【JS】websocket原理

TCP是面向连接的协议,其显著特征是在传输之前需要3次握手形成会话。

【JS】websocket原理

只有会话形成后,服务器端和客户端才能相互发送数据。在创建会话的过程中,服务器端和客户端分别提供一个套接字,
这两个套接字共同形成一个连接。服务器端和客户端则通过套接字实现两者之间连接的操作。

http网络通信的所有报文信息如下,报文分为四部分。

$ curl -v http://127.0.0.1:1337

//第一部分:是经典的TCP三次握手,这样就建立了连接

* About to connect() to 127.0.0.1 port 1337 (#0)

* Trying 127.0.0.1...

* connected

* Connected to 127.0.0.1 (127.0.0.1) port 1337 (#0)

//第二部分:在完成握手之后,客户端向服务器端发送请求报文。

> GET / HTTP/1.1

> User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8r zlib/1.2.5

> Host: 127.0.0.1:1337

> Accept: */*

>

//第三部分:服务器端完成处理后,向客户端发送的响应内容,包括响应头和响应体。

< HTTP/1.1 200 OK

< Content-Type: text/plain

< Date: Sat, 06 Apr 2013 08:01:44 GMT

< Connection: keep-alive

< Transfer-Encoding: chunked

<

Hello World

第四部分:结束会话的信息

* Connection #0 to host 127.0.0.1 left intact

* Closing connection #0

注意:报文的内容主要是两部分,报文头和报文体,上一个例子中,使用的是get请求,报文头的部分是上边报文信息中>和<的部分。在响应报文中,有一个报文体,是Hello World。

2.WebSocket

使用websocket的话,网页客户端只需一个TCP链接即可完成双向通信,在服务端与客户端频繁通信时,无须频繁断开连接和重发请求。连接可以得到高效应用。

websocket与HTTP有如下好处:

  • 客户端与服务器只建立一个tcp连接,可以使用更少的连接
  • websocket服务器端可以推送数据到客户端,这远比HTTP请求响应模式更灵活,更高效。
  • 有更轻量级的协议头,减少数据传送量

相比http,websocket更接近于传输层协议,它并没有在http的基础上模拟服务器端的推送,而是在tcp上定义独立的协议,但是websocket的握手部分是由Http完成的。

websocket分为握手和数据传输两部分,其中握手使用了http进行。

1)WebSocket握手
客户端建立连接是,通过HTTP发起请求报文。如下所示:

GET /chat HTTP/1.1

Host: server.example.com

//请求服务端升级协议为WebSocket

Upgrade: websocket

Connection: Upgrade

//用于安全校验

Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

//指定子协议和版本号

Sec-WebSocket-Protocol: chat, superchat

Sec-WebSocket-Version: 13

服务器端在处理完请求后,响应如下报文:

HTTP/1.1 101 Switching Protocols

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

Sec-WebSocket-Protocol: chat

这段报文将告诉客户端,正在更换协议,更新为应用层协议websocket,并在当前的套接字上应用新的协议。
剩余的字段分别表示服务器端基于Sec-WebSocket-Key生成的字符串和选中的子协议。客户端将会校验Sec-WebSocket-Accept的值,如果成功,将开始接下来的数据传输。

2)WebSocket数据传输

在顺利握手后,当前连接将不再进行http交互,而是开始websocket的数据帧协议,实现客户端与服务器的数据交换。
协议升级的过程如下:

【JS】websocket原理

当客户端调用send()发送数据时,服务器端触发onmessage(),当服务器端调用send()发送数据时,客户端的onmessage()触发,当我们调用send()发送一条数据时,协议可能将这个数据封装为一帧或多帧数据,然后逐帧发送。
为了安全考虑,客户端需要发送的数据帧进行掩码处理,服务器一旦收到无掩码帧,比如中间拦截破坏,连接将会关闭。服务器发送到客户端的数据帧无需做掩码,如果客户端收到了带掩码的数据帧,连接也将关闭。
在websocket中的数据帧的定义,每8位为一列,也就是一个字节,其中每一位都有它的意义:

【JS】websocket原理

  • fin,如果这一帧是最后一帧,这个fin为为1,其余情况为0.
  • rsv1、rsv2、rsv3,都是一位长,用于标识扩展,当有已协商的扩展时,这些值可能为1,其余情况为0。
  • opcode,4位长,可以用来表示0~15的值,用于解释当前数据帧,0表示附加数据帧,1表示文本数据帧,2表示二进制数据帧,8表示发送一个连接关闭的数据帧,9表示ping数据帧,10表示pong数据帧,其余值暂时没有定义。瓶数据帧和pong数据帧用于心跳检测,当一端发送一个ping数据帧时,另一端必须发送pong数据帧作为回应,告知对方这一端仍然处于响应状态。
  • masked,表示是否进行掩码处理,1位长度,客户端发送给服务器时为1,服务器发送回客户端时为0.
  • payload length:一个7、7+16或7+64位长的数据为,标识数据的长度,如果值在0~125之间那么该值就是数据的真实长度,如果是126,则后面16位的值是数据的真实长度,如果是127,则后面64位的值是数据的真实长度。
  • making key,当masked为1时,这里是一个32位长的数据位,用于解密数据。
  • payload data,我们的目标数据,位数为8的倍数。

客户端发送消息时,需要构造一个或多个数据帧协议报文,例如我们发送一个hello world,这个比较短,不存在分割多个数据帧的情况,并且以文本方式发送,他的payload length长度为96(12字节*8位/字节),二进制表示为110000。所以报文应该是:

fin(1) + res(000) + opcode(0001) + masked(1) + payload length(1100000) + masking key(32位) + payload

data(hello world!加密后的ܾ二进制)

服务器回复的是yakexi,这个无需掩码,形式如下:

fin(1) + res(000) + opcode(0001) + masked(0) + payload length(1100000) + payload data(yakexi的ܾ二进制)

以上是 【JS】websocket原理 的全部内容, 来源链接: utcz.com/a/97288.html

回到顶部