Web端即时通信技术-WebSocket

这篇具有很好参考价值的文章主要介绍了Web端即时通信技术-WebSocket。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

最近在做项目的时候,遇到了一个前端页面需要实时刷新的功能,一种方法是我们通过短轮询的方式,但这种方式虽然简单,但是无用的请求过多,占用资源,并且如果是对数据要求高较高的场景,就不适用了。

 

这个时候就要考虑应用长连接了,最开始想到的是,Http1.1以后支持的长连接,但是经过实践后发现,这里可能存在一个误解:Http协议是基于请求/响应模式的,因此客户端请求后只要服务端给了响应,本次Http请求就结束了,没有长连接这么一说,那么自然也就没有短连接这么一说了。也就是说,在这样一个HTTP连接中,可以发送多个Request,接收多个Response。但是Request和Response永远是相对应的,也就是说一个request只能有一个response。并且这个response也是被动的,不能主动发起。

所谓的HTTP长连接和短连接,其实本质上说的是TCP连接。TCP连接是一个双向的通道,它是可以保持一段时间不关闭的,因此TCP连接才有真正的长连接和短连接这么一说。

那么下面我们一起来看下WebSocket是如何实现的。

什么是WebSocket?

WebSocket是一种在单个TCP连接上进行全双工通信的协议,使得客户端与服务端之间的数据交换变得更加简单,允许服务端主动向客户端推送数据,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

这里先来区分下三者的含义:

  • 单工:数据传输只允许在一个方向上传输,只能一方发送数据,另一方来接受数据并发送;例如:对讲机。

  • 半双工:数据传输允许两个方向上的传输,但是同一时间内,只可以有一方发送或接收消息,并存在最大传输距离的限制。

  • 全双工:接口可以同时发送和接收数据,最大吞吐量可达到双倍速率,且消除了半双工的物理距离限制。

解决了什么问题?

客户端(浏览器)和服务器进行通信,只能由客户端发起ajax请求,才能进行通信,服务端无法主动向客户端推送消息。像我们常见的一些场景:体育赛事、聊天室、实时位置之类的场景时,客户端要获取服务器端的变化,就只能通过轮询(定时请求)的方式来了解服务器端有没有新的信息变化

轮询效率低,非常浪费资源(需要不断的发送请求,不停连接服务器)

WebSocket的出现,让服务器端可以主动向客户端发送信息,使得浏览器具备了实时双向通信的能力。

实现案例:

前端示例:

// websocket.js   
const WebSocket = require('ws')
const events = []
let latestTimestamp = Date.now()
const clients = new Set()//连接着的socket数组

const EventProducer = () => {
  const event = {
    id: Date.now(),
    timestamp: Date.now()
  }
  events.push(event)
  latestTimestamp = event.timestamp
  
  // 推送给所有连接着的socket
  clients.forEach(client => {
    client.ws.send(JSON.stringify(events.filter(event => event.timestamp > client.timestamp)))
    client.timestamp = latestTimestamp
  })
}

// 每10秒生成一个新的事件
setInterval(() => {
  EventProducer()
}, 10000)

// 启动socket服务器
const wss = new WebSocket.Server({ port: 8080 })
wss.on('connection', (ws, req) => {
  console.log('client connected')
  // 首次连接,推送现存事件
  ws.send(JSON.stringify(events))
  const client = {
    timestamp: latestTimestamp,
    ws,
  }
  clients.add(client)//将连接放入数组
  ws.on('close', _ => {
    clients.delete(client)
  })
})
var timestampRef={current:0}
    var eventsRef={current:[]}
     const ws = new WebSocket(`ws://localhost:8080/ws?timestamp=${timestampRef.current}`)
    ws.addEventListener('open', e => {
      console.log('successfully connected')
    })
    ws.addEventListener('close', e => {
      console.log('socket close')
    })
    ws.addEventListener('message', (ev) => {
      const latestEvents = JSON.parse(ev.data)
      if (latestEvents && latestEvents.length) {
        timestampRef.current = latestEvents[latestEvents.length - 1].timestamp
         //注意latestEvents数据是后端新生成的数据,前端需要自己拼上老数据
        eventsRef.current = [...eventsRef.current, ...latestEvents]
        console.log(eventsRef)
      }
    })

服务端代码(基于SpringBoot):

WebSocketConfig

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Resource
    private HttpAuthHandler handler;

    @Resource
    private WebSocketInterceptor interceptor;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(handler, "/hello")
                .addInterceptors(interceptor)
                .setAllowedOrigins("*");
    }
}

HttpAuthHandler

@Component
public class HttpAuthHandler extends TextWebSocketHandler {

    /**
     * 建立成功事件
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        super.afterConnectionEstablished(session);
    }

    /**
     * 接受消息事件
     * @param session
     * @param message
     * @throws Exception
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String payload = message.getPayload();
        Object token = session.getAttributes().get("token");
        System.out.println("server 接收到 " + token + " 发送的 " + payload);
        session.sendMessage(new TextMessage("server 发送给 " + token + " 消息 " + payload + " " +    LocalDateTime.now().toString()));
    }

    /**
     * 断开连接时
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        super.afterConnectionClosed(session, status);
    }
}

WebSocketInterceptor

public class WebSocketInterceptor implements HandshakeInterceptor {

    /**
     * 握手前
     *
     * @param request
     * @param response
     * @param wsHandler
     * @param attributes
     * @return
     * @throws Exception
     */
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
        System.out.println("握手开始");
        // 获得请求参数
        Map<String, String> paramMap = HttpUtil.decodeParamMap(request.getURI().getQuery(), StandardCharsets.UTF_8);
        String uid = paramMap.get("token");
        if (StrUtil.isNotBlank(uid)) {
            // 放入属性域
            attributes.put("token", uid);
            System.out.println("用户 token " + uid + " 握手成功!");
            return true;
        }
        System.out.println("用户登录已失效");
        return false;
    }

    /**
     * 握手后
     *
     * @param request
     * @param response
     * @param wsHandler
     * @param exception
     */
    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
        System.out.println("握手完成");
    }
}

测试:Web端即时通信技术-WebSocket

Web端即时通信技术-WebSocket

上边简单实现了一个webSocket通信。实际的东西还有很多,比如webSocket扩展,心跳检测,数据加密,身份认证等知识点。但自己也需要再去研究,所以先不做介绍了。

到这里,基本上使用应该是没问题了,下面我们来继续来继续探讨下有关其实现方面的细节。

实现原理

WebSocket是位于应用层的一个应用层协议,它需要依赖HTTP协议进行一次握手,握手成功后,数据就直接从TCP通道传输,与HTTP无关了。也就是分为握手阶段和数据传输阶段,即:HTTP握手+双工的TCP连接。

下面我们分别来看一下这两个阶段的具体实现原理。

一、握手阶段

客户端发送消息:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Version: 13

在HTTP Header中设置Upgrade字段,其字段值为websocket,并在Connection字段提示Upgrade,服务端若支持WebSocket协议,并同意握手,可以返回如下结构:


HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
Sec-WebSocket-Version: 13

我们来详细讨论WebSocket握手的细节,发现除了设置Upgrade之外,还需要设置其他的Header字段。

  • Sec-WebSocket-Key:必传,由客户端随机生成的 16 字节值, 然后做 base64 编码, 客户端需要保证该值是足够随机, 不可被预测的 (换句话说, 客户端应使用熵足够大的随机数发生器), 在 WebSocket 协议中, 该头部字段必传, 若客户端发起握手时缺失该字段, 则无法完成握手

  • Sec-WebSocket-Version:必传, 指示 WebSocket 协议的版本, RFC 6455 的协议版本为 13, 在 RFC 6455 的 Draft 阶段已经有针对相应的 WebSocket 实现, 它们当时使用更低的版本号, 若客户端同时支持多个 WebSocket 协议版本, 可以在该字段中以逗号分隔传递支持的版本列表 (按期望使用的程序降序排列), 服务端可从中选取一个支持的协议版本

  • Sec-WebSocket-Protocol :可选, 客户端发起握手的时候可以在头部设置该字段, 该字段的值是一系列客户端希望在与服务端交互时使用的子协议 (subprotocol), 多个子协议之间用逗号分隔, 按客户端期望的顺序降序排列, 服务端可以根据客户端提供的子协议列表选择一个或多个子协议

  • Sec-WebSocket-Extensions:可选, 客户端在 WebSocket 握手阶段可以在头部设置该字段指示自己希望使用的 WebSocket 协议拓展

服务端若支持 WebSocket 协议, 并同意与客户端握手, 则应返回 101 的 HTTP 状态码, 表示同意协议升级, 同时应设置 Upgrade 字段并将值设置为 websocket, 并将 Connection 字段的值设置为 Upgrade, 这些都是与标准 HTTP Upgrade 机制完全相同的, 除了这些以外, 服务端还应设置与 WebSocket 相关的头部字段:

  • Sec-WebSocket-Accept:必传, 客户端发起握手时通过 | Sec-WebSocket-Key | 字段传递了一个将随机生成的 16 字节做 base64 编码后的字符串, 服务端若接收握手, 则应将该值与 WebSocket 魔数 (Magic Number) "258EAFA5-E914-47DA- 95CA-C5AB0DC85B11" 进行字符串连接, 将得到的字符串做 SHA-1 哈希, 将得到的哈希值再做 base64 编码, 最终的值便是该字段的值

  • Sec-WebSocket-Protocol:可选, 若客户端在握手时传递了希望使用的 WebSocket 子协议, 则服务端可在客户端传递的子协议列表中选择其中支持的一个, 服务端也可以不设置该字段表示不希望或不支持客户端传递的任何一个 WebSocket 子协议

  • Sec-WebSocket-Extensions:可选, 与 Sec-WebSocket-Protocol 字段类似, 若客户端传递了拓展列表, 服务端可从中选择其中一个作为该字段的值, 若服务端不支持或不希望使用这些扩展, 则不设置该字段

  • Sec-WebSocket-Version:必传, 服务端从客户端传递的支持的 WebSocket 协议版本中选择其中一个, 若客户端传递的所有 WebSocket 协议版本对服务端来说都不支持, 则服务端应立即终止握手, 并返回 HTTP 426 状态码, 同时在 Header 中设置 | Sec-WebSocket-Version | 字段向客户端指示自己所支持的 WebSocket 协议版本列表

二、数据传输阶段

通信的数据是基于帧(frame)的,可以传输文本数据,也可以直接传输二进制数据,效率高,当然,开发者相应的也需要考虑封包、拆包、编号等细节。

Web端即时通信技术-WebSocket

三、优缺点

优点:

  • 节约带宽
    不停地轮询服务端数据这种方式,使用的是http协议,head信息很大,有效数据占比低, 而使用WebSocket方式,头信息很小,有效数据占比高。

  • 实时性
    考虑到服务器压力,使用轮询方式不可能很短的时间间隔,否则服务器压力太多,所以轮询时间间隔都比较长,好几秒,设置十几秒。而WebSocket是由服务器主动推送过来,实时性是最高的。

  • 压缩效果好

  • 可以支持扩展

缺点:

  • 不兼容低版本IE

总结

WebSocket是HTML5开始提供的一种独立在单个TCP连接上进行全双工通讯的有状态协议,并且还能支持二进制帧、扩展协议、部分自定义的自协议、压缩等特性。

目前看来,WebSocket可以完美替代AJAX轮询和Comet,但是某些场景还是不能替代SSE,WebSocket和SSE各有所长。文章来源地址https://www.toymoban.com/news/detail-456538.html

到了这里,关于Web端即时通信技术-WebSocket的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Web端即时通讯技术(SEE,webSocket)

    服务端和客户端应该怎么通信才能实现客户端能获取服务端最新消息让用户有更好的交互体验,如果是正常的发送一个请求首先要建立TCP连接然后等到服务器返回,如果是开发者可以通过发包情况就能知道建立连接成功与否,是否是在等待服务器响应,但是做为非开发者的普

    2024年02月15日
    浏览(47)
  • 浅谈卫星通信技术

    目录 1.卫星的概念 2.卫星的具体作用 3.利用卫星进行通信的优势 4.卫星通信带来的技术变革         卫星是指在地球轨道上运行的天体或人造物体。一般来说,我们所说的卫星主要指人造卫星,它是由人类设计、制造并送入轨道的人造宇宙飞行器。         人造卫星通

    2024年02月11日
    浏览(32)
  • 物联网通信技术

    UWB:超宽带无线通信技术(UWB)是一种无载波通信技术,UWB不使用载波,而是使用短的能量脉冲序列,并通过正交频分调制或直接排序将脉冲扩展到一个频率范围内。 NFC:全称是Near Field  Communication,即“近场通信”,也叫“近距离无线通信”。 ARQ:自动重传请求(Automati

    2024年02月09日
    浏览(34)
  • 即时通信的方法和webSocket的具体使用

    之前遇到过需要即时通讯的场景,刚开始使用的是通过轮询的方式,定时器3秒向服务器请求一次数据,后面发现如果在手机端长时间打开使用此功能的页面,可能会发生手机发热,甚至卡顿的现象。最后改用webSocket,可以实现全双工通信,让服务器主动向客户端发送请求。

    2024年02月15日
    浏览(34)
  • 世界前沿技术发展报告2023《世界信息技术发展报告》(六)网络与通信技术

    资料来自:《世界前沿技术发展报告2023》和网络 随着满足智慧交互、沉浸式拓展现实(Extended Reality, XR)全息通信、数字孪生等新兴技术的超高速率传输需求,新一代通信技术成为全球研究热点。伴随着5G在全球范围内的陆续应用,全球通信强国正开启对下一代网络技术6G的研发

    2024年02月07日
    浏览(38)
  • 物联网中的通信技术

    阅读引言: 本文主要大致为大家带来物联网中的常见的通信方式的知识梳理。 目录 一、概述 二、无线通信技术 1.物联网电子标签 RFID 1.1 RFID 概念 1.2 RFID 系统组成 2.WI-FI技术 3.UWB技术 4.ZigBee技术 5.NFC技术 6.蓝牙技术 7.EnOcean技术              物联网的通信层担负着极其重

    2024年01月18日
    浏览(37)
  • 无线网络通信技术详细介绍

    以下是对各类网络各自常见和常用的通信技术进行简单介绍。 一、无线广域网(WWAN) 无线广域网WWAN(Wireless Wide Area Networks)主要是为了满足超出一个城市范围的信息交流和网际接入需求,让用户可以和在遥远地方的公众或私人网络建立无线连接。在无线广域网的通信中一般要用

    2024年02月08日
    浏览(47)
  • 元宇宙挑战现实世界无线通信技术

    导 言 事 件 2021年10月28日,在名为Facebook Connect的年度大会上,Facebook宣布,公司名称将更改为“Meta”,这是元宇宙Metaverse的前缀,意思是包含万物无所不连。标志着这一世界级的科技巨头从传统的社交媒体公司,all in元宇宙的战略决心。这一信息也将酝酿多年的元宇宙概念研

    2024年02月05日
    浏览(45)
  • W3电力线载波通信技术

    CK_Label_W3 CK_Label_W3(外接供电版) 产品型号 CK_Label_W3 尺寸 114.5*44.5*19mm 屏幕尺寸 2.9 inch 分辨率 296*128 像素密度 112dpi 显示技术 电子墨水屏显示 显示颜色 黑/白 外观颜色 白色 按键 4 指示灯 4 RGB灯 灯光颜色 7种(红/绿/蓝/黄/紫/白/青) 工作温度 0-50℃ 视角 180° 支持内容格式 文本

    2024年02月08日
    浏览(44)
  • 物联网通信技术复习题整理

    1【单选题】三层结构类型的物联网不包括( )。 A、感知层 B、网络层 C、应用层 D、会话层 答案:D 2【单选题】物联网的核心是( )。 A、应用 B、产业 C、技术 D、标准 答案:A 3【单选题】属于感知控制层通信技术的是( ). A、ZigBee技术 B、3G网络 C、4G网络 D、局域网 答案:

    2024年02月09日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包