前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >websocket

websocket

作者头像
用户10106350
发布2022-10-28 14:37:57
2.6K0
发布2022-10-28 14:37:57
举报
文章被收录于专栏:WflynnWeb

websocket在什么背景下诞生?

短轮询(Polling)

短轮询(Polling)的实现思路就是 浏览器端 每隔几秒钟向 服务器端 发送http请求,服务端在收到请求后,不论是否有数据更新,都直接进行响应。 在服务端响应完成,就会关闭这个Tcp连接 ,如下图所示:

示例代码实现如下:

代码语言:javascript
复制
function Polling() {
    fetch(url).then(data => {
        // somthing
    }).catch(err => {
        console.log(err);
    });
}
setInterval(polling, 5000);
  • 优点:可以看到实现非常简单,它的 兼容性 也比较好的只要 支持http协议 就可以用这种方式实现。
  • 缺点:但是它的缺点也很明显就是非常的消耗资源,因为建立 Tcp 连接是非常消耗资源的,服务端响应完成就会关闭这个 Tcp 连接,下一次请求再次建立 Tcp 连接。
长轮询(Long-Polling)

客户端发送请求后服务器端 不会立即 返回数据,服务器端会 阻塞请求 连接不会 立即断开 ,直到服务器端 有数据更新或者是连接超时 才返回,客户端才再次发出请求新建连接、如此反复从而获取最新数据。大致效果如下:

客户端的代码如下:

代码语言:javascript
复制
function LongPolling() {
    fetch(url).then(data => {
        LongPolling();
    }).catch(err => {
        LongPolling();
        console.log(err);
    });
}
LongPolling();
  • 优点:长轮询和短轮询比起来,明显减少了很多不必要的http请求次数,相比之下节约了资源。
  • 缺点:连接挂起也会导致资源的浪费。
WebSocket

WebSocket是一种协议,是一种与HTTP 同等的网络协议,两者都是应用层协议,都基于 TCP 协议。但是 WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据。同时,WebSocket在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了。

相比于短轮询、长轮询的每次“请求-应答”都要client 与 server 建立连接的模式,WebSocket 是一种长连接的模式。就是一旦WebSocket 连接建立后,除非client 或者 server 中有一端主动断开连接,否则每次数据传输之前都不需要HTTP 那样请求数据。

另外,短轮询、长轮询服务端都是被动的响应,属于单工通信。而websocket客户端、服务端都能主动的向对方发送消息,属于全双工通信。

WebSocket 对象提供了一组 API,用于创建和管理 WebSocket 连接,以及通过连接发送和接收数据。浏览器提供的WebSocket API很简洁,调用示例如下:

代码语言:javascript
复制
var ws = new WebSocket('wss://example.com/socket'); // 创建安全WebSocket 连接(wss)
ws.onerror = function (error) { ... } // 错误处理
ws.onclose = function () { ... } // 关闭时调用
ws.onopen = function () { ws.send("Connection established. Hello server!");} // 连接建立时调用向服务端发送消息
ws.onmessage = function(msg) {  ... }// 接收服务端发送的消息复制代码

HTTP、WebSocket 等应用层协议,都是基于 TCP 协议来传输数据的。我们可以把这些高级协议理解成对 TCP 的封装。既然大家都使用 TCP 协议,那么大家的连接和断开,都要遵循 TCP 协议中的三次握手和四次握手 ,只是在连接之后发送的内容不同,或者是断开的时间不同。对于 WebSocket 来说,它必须依赖 HTTP 协议进行一次握手 ,握手成功后,数据就直接从 TCP 通道传输,与 HTTP 无关了。

websocket是怎样握手的?

  • 浏览器、服务器建立TCP连接,三次握手。这是通信的基础,传输控制层,若失败后续都不执行。
  • TCP连接成功后,浏览器通过HTTP协议向服务器发送带有Upgrade头的HTTP Request消息

Connection:HTTP1.1中规定Upgrade只能应用在直接连接中。带有Upgrade头的HTTP1.1消息必须含有Connection头,因为Connection头的意义就是,任何接收到此消息的人(往往是代理服务器)都要在转发此消息之前处理掉Connection中指定的域(即不转发Upgrade域)。 Upgrade是HTTP1.1中用于定义转换协议的header域。如果服务器支持的话,客户端希望使用已经建立好的HTTP(TCP)连接,切换到WebSocket协议。 Sec-WebSocket-Key是一个Base64encode的值,这个是客户端随机生成的,用于服务端的验证,服务器会使用此字段组装成另一个key值放在握手返回信息里发送客户端。 Sec-WebSocket-Version标识了客户端支持的WebSocket协议的版本列表。 Sec-WebSocket-Extensions是客户端用来与服务端协商扩展协议的字段,permessage-deflate表示协商是否使用传输数据压缩,client_max_window_bits表示采用LZ77压缩算法时,滑动窗口相关的SIZE大小。 Sec_WebSocket-Protocol是一个用户定义的字符串,用来区分同URL下,不同的服务所需要的协议,标识了客户端支持的子协议的列表。

  • 服务器收到客户端的握手请求后,同样采用HTTP协议回馈。

HTTP的版本为HTTP1.1,返回码是101,表示升级到websocket协议 Connection字段,包含Upgrade Upgrade字段,包含websocket Sec-WebSocket-Accept字段,详细介绍一下: Sec-WebSocket-Accept字段生成步骤: 客户端通过验证服务端返回的Sec-WebSocket-Accept的值, 来确定两件事情:

  1. 服务端是否理解WebSocket协议, 如果服务端不理解,那么它就不会返回正确的Sec-WebSocket-Accept,则建立WebSocket连接失败。
  2. 服务端返回的Response是对于客户端的此次请求的,而不是之前的缓存。主要是防止有些缓存服务器返回缓存的Response.
  3. 将Sec-WebSocket-Key与协议中已定义的一个GUID “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”进行拼接。
  4. 将步骤1中生成的字符串进行SHA1编码。
  5. 将步骤2中生成的字符串进行Base64编码。

  • 至此,握手过程就完成了,此时的TCP连接不会释放。客户端和服务端可以互相通信了。

websocket如何身份认证?

大体上Websocket的身份认证都是发生在握手阶段,通过请求中的内容来认证。一个常见的例子是在url中附带参数。

代码语言:javascript
复制
new WebSocket("ws://localhost:3000?token=xxxxxxxxxxxxxxxxxxxx");

淘宝的直播弹幕也是用这种方式做的身份认证。另外,websocket是采用http协议握手的,可以用请求中携带cookie的方式做身份认证。

以npm的ws模块实现为例,其创建Websocket服务器时提供了verifyClient方法。

代码语言:javascript
复制
const wss = new WebSocket.Server({
  host: SystemConfig.WEBSOCKET_server_host,
  port: SystemConfig.WEBSOCKET_server_port,
  // 验证token识别身份
  verifyClient: (info) => {
    const token = url.parse(info.req.url, true).query.token
    let user
    console.log('[verifyClient] start validate')
    // 如果token过期会爆TokenExpiredError
    if (token) {
      try {
        user = jwt.verify(token, publicKey)
        console.log(`[verifyClient] user ${user.name} logined`)
      } catch (e) {
        console.log('[verifyClient] token expired')
        return false
      }
    }
    // verify token and parse user object
    if (user) {
      info.req.user = user
      return true
    } else {
      info.req.user = {
        name: `游客${parseInt(Math.random() * 1000000)}`,
        mail: ''
      }
      return true
    }
  }
})

相关的ws源码位于 ws/websocket-server

代码语言:javascript
复制
// ...
  if (this.options.verifyClient) {
    const info = {
      origin: req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`],
      secure: !!(req.connection.authorized || req.connection.encrypted),
      req
    };

    if (this.options.verifyClient.length === 2) {
      this.options.verifyClient(info, (verified, code, message) => {
        if (!verified) return abortHandshake(socket, code || 401, message);
        this.completeUpgrade(extensions, req, socket, head, cb);
      });
      return;
    }

    if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);
  }
  this.completeUpgrade(extensions, req, socket, head, cb);
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-03-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 WflynnWeb 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • websocket在什么背景下诞生?
    • 短轮询(Polling)
      • 长轮询(Long-Polling)
        • WebSocket
        • websocket是怎样握手的?
        • websocket如何身份认证?
        相关产品与服务
        云直播
        云直播(Cloud Streaming Services,CSS)为您提供极速、稳定、专业的云端直播处理服务,根据业务的不同直播场景需求,云直播提供了标准直播、快直播、云导播台三种服务,分别针对大规模实时观看、超低延时直播、便捷云端导播的场景,配合腾讯云视立方·直播 SDK,为您提供一站式的音视频直播解决方案。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档