百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

初学者必看的WebSocket技术入门篇!

zhezhongyun 2025-01-14 19:06 40 浏览


目录

WebSocket入门篇
一、是什么?
二、为什么出现
三、有什么用?
四、如何使用?
	1、WebSocket 客户端
			1)源码示例
			2) WebSocket 事件
  2、WebSocket 服务端
			1)概述
			2)源码示例
			3)注解介绍
五、结束语

WebSocket入门篇

小郭最近接到了一个业务需求,要在页面上展示一些业务数据。业务方要求数据展示要实时更新,因此常规的前端轮询查询方式肯定是行不通了,会导致数据更新有延迟。

小郭想起来以前上大学时接触过的WebSocket技术是可以支持业务方的要求,由于学习时间有点久,需要重新拿起来学习一下了。

本篇文章将WebSocket的基础知识进行了较为全面的总结,希望大家和小郭一样,通过本篇文章的学习可以掌握WebSocket的基本使用。

一、是什么?

WebSocket 是一种网络传输协议,在2008年诞生,2011年成为了国际标准,基于它的WebSocket API也被W3C定为标准,目前所有浏览器都已经支持该协议了。

WebSocket 可实现在单个 TCP 连接上进行全双工通信,位于 OSI 模型的应用层。它使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。

二、为什么出现

互联网早期,很多网站为了实现推送技术,所用的技术都是轮询。轮询是指在特定的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式有一个很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

而目前比较新的技术是Comet。这种技术虽然可以双向通信,但依然需要反复发出请求。而且在Comet中,普遍采用的长链接,也会消耗服务器资源。

在这种情况下,HTML5定义了WebSocket协议,相对于Http和Comet,只需要建立一次连接,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

三、有什么用?

WebSocket的特点

  • 更高的实时性

协议是全双工类型的,服务器可以随时主动给客户端推送数据。相对于HTTP短轮询操作需要等待客户端请求服务端才能响应,实时性明显更高。即使和Comet等长轮询来比较,其也能在短时间内传递更多的数据。

  • 更好的数据格式支持

WebSocket支持文本和二进制这两种格式的数据,而且定义了二进制帧,相对比HTTP,可以更容易处理二进制内容。

  • 扩展性强

WebSocket支持用户扩展协议、实现部分自定义的子协议。比如部分浏览器支持的压缩功能。Websocket在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以大大提高压缩率。

  • 较少的传输开销

在连接创建后,服务端和客户端交换数据时,用于协议元数据控制的数据包长度比较小。相比HTTP请求每次都需要携带完整头部,此项内容传输开销大大减少。

  • 保持连接状态

与HTTP不同的是,Websocket是一种有状态的协议,因为它需要先建立连接,之后在连接关闭之前的每次通信时都可以省略部分状态信息。而HTTP请求每次都需要建立连接(握手), 而且每次请求可能都需要携带状态信息(如身份认证鉴权等)。

  • 建立在 TCP 协议之上,服务器端的实现比较容易
  • 没有同源限制,客户端可以与任意服务器通信
  • 协议标识符是ws(如果加密,则为wss),服务器网址就是 URL
  • 兼容HTTP协议

和HTTP一样,默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

由于 WebSocket 拥有上述的特点,所以它被广泛地应用在下面的领域:

  • 即时聊天通信
  • 多玩家游戏
  • 在线协同编辑/编辑
  • 实时数据流的拉取与推送
  • 体育/游戏实况
  • 实时地图位置
  • 即时Web应用程序:即时Web应用程序使用一个Web套接字在客户端显示数据,这些数据由后端服务器连续发送。在WebSocket中,数据被连续推送/传输到已经打开的同一连接中,这就是为什么WebSocket更快并提高了应用程序性能的原因。 例如在交易网站或比特币交易中,这是最不稳定的事情,它用于显示价格波动,数据被后端服务器使用Web套接字通道连续推送到客户端。
  • 游戏应用程序:在游戏应用程序中,你可能会注意到,服务器会持续接收数据,而不会刷新用户界面。屏幕上的用户界面会自动刷新,而且不需要建立新的连接,因此在WebSocket游戏应用程序中非常有帮助。
  • 聊天应用程序:聊天应用程序仅使用WebSocket建立一次连接,便能在订阅户之间交换,发布和广播消息。它重复使用相同的WebSocket连接,用于发送和接收消息以及一对一的消息传输。

四、如何使用?

由上图可知:目前主流的 Web 浏览器都支持 WebSocket,所以我们可以在大多数项目中放心地使用它。

Web 浏览器和服务器都必须实现 WebSockets 协议来建立和维护连接。由于 WebSockets 连接长期存在,与典型的 HTTP 连接不同,对服务器有重要的影响。

基于多线程或多进程的服务器无法适用于 WebSockets,因为它旨在打开连接,尽可能快地处理请求,然后关闭连接。任何实际的 WebSockets 服务器端实现都需要一个异步服务器。

下面通过一些案例介绍WebSocket的客户端和服务端基本使用。

1、WebSocket 客户端

在客户端,支持 WebSocket 的 Web 浏览器将通过 WebSocket 对象公开所有必需的客户端功能(主要指支持 Html5 的浏览器)。

1)源码示例

<script type="text/javascript">
    var websocket=null
    if('WebSocket' in window){
        //调用service请求,获取信息
        topic=new WebSocket("ws://localhost:8082/websocket");
    }else{
        alert("该浏览器不支持WebSocket!")
    }

    topic.onopen=function(event){
        console.log("建立连接!");
    }


    topic.onclose=function(event){
        console.log("连接关闭!");
    }

    topic.onmessage=function(event){
        console.log("收到消息!"+event.data);
        document.getElementById("info").textContent +=event.data;
        //弹窗提醒
    }

    topic.onerror=function(){
        alert("websocket发生错误!");
    }

    topic.onbeforeunload=function(){
        topic.close();
    }
</script>

2) WebSocket 事件

以下是 WebSocket 对象的相关事件:

事件

含义

onopen

连接建立时触发

onmessage

客户端接收服务端数据时触发

onerror

通信发生错误时触发

onclose

连接关闭时触发

onbeforeunload

当浏览器窗口关闭或者刷新时触发

2、WebSocket 服务端

1)概述

WebSocket 在服务端的实现非常丰富。Node.js、Java、C++、Python 等多种语言都有自己的解决方案。

本篇仅介绍小郭在学习 WebSocket 过程中接触过的 Java服务端解决方案。

Java 的 web能力 一般都依托于 servlet 容器。

小郭了解的 servlet 容器有:Tomcat、Jetty、Resin。其中 Tomcat7、Jetty7 及以上版本均开始支持 WebSocket(推荐较新的版本,因为随着版本的更迭,对 WebSocket 的支持可能有变更)。

目前流行的Spring 框架对 WebSocket 也提供了支持,主要依赖下面的jar包:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-websocket</artifactId>
  <version>${spring.version}</version>
</dependency>

基于Spring之上的SpringBoot对WebSocket提供了良好的整合,主要依赖下面的jar包:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-websocket</artifactId>
  <version>${springboot.version}</version>
</dependency>

本篇接下来采用SpringBoot框架来介绍如何整合WebSocket。

2)源码示例

下面记录一下 SpringBoot程序如何整合WebSocket。

为了减少篇幅,demo项目采用前后端不分离的方式,因此也包含了客户端实现代码。

  • a、引入jar包

这里直接创建前后端不分离的web应用程序(实际生产中web前端和后端是分离的工程)

 <!-- 添加Web依赖 -->
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-thymeleaf</artifactId>
 </dependency>
 <!--websocket-->
 <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
 </dependency>
  • b、配置页面信息

在application.properties中添加页面相关配置

server.port=8082
# Spring thymeleaf
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/pages/
spring.thymeleaf.suffix=.html
  • c、配置websocket

WebSocket核心都在这里。

因为WebSocket是类似客户端服务端的形式(采用ws协议),那么这里的WebSocketServer其实就相当于一个ws协议的Controller

直接@ServerEndpoint("/websocket") 、@Component启用即可,然后在里面实现@OnOpen开启连接,@onClose关闭连接,@onMessage接收消息等事件方法。

 @Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
package com.gyd.websocket;

import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.CopyOnWriteArraySet;

@Component
//这个注解用来标记一个类是 WebSocket 的处理器。然后,我们可以在这个类的方法签名上使用一系列注解来表明所修饰的方法是某种事件类型的回调
@ServerEndpoint("/websocket")
public class WebSocketService {
    private Session session;

    //保存连接
    private static CopyOnWriteArraySet<WebSocketService> webSocketService = new CopyOnWriteArraySet<>();

    /**
     * 建立连接
     * @param session
     */
    @OnOpen
    public void opOpen(Session session) {
        this.session = session;
        webSocketService.add(this);
        System.out.println("有新的连接=============》" + webSocketService.size());
    }

    /**
     * 断开连接
     */
    @OnClose
    public void onClose() {
        webSocketService.remove(this);
        System.out.println("断开连接=============》" + webSocketService.size());
    }

    /**
     * 接收客户端消息
     * @param message
     */
    @OnMessage
    public void onMessage(String message) {
        System.out.println("收到客户端消息" + message);
    }

    /**
     * 发送消息到客户端
     * @param message
     */
    public void sendMessage(String message) {
        for (WebSocketService webSocketService2 : webSocketService) {
            System.out.println("广播消息" + message);
            webSocketService2.session.getAsyncRemote().sendText(message);
        }
    }
     /**
     * 传输消息错误触发事件
     * @param error
     */
    @OnError
    public void onError(Throwable error) {

    }
}
  • d、创建接口

controller中只有一个简单的界面跳转操作和模拟造数操作,其他的不需要。

页面访问接口:/show/topic (对应页面名称)

websocket数据模拟接口:/show/createOrder

 package com.gyd.contoller;

import com.gyd.websocket.WebSocketService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.UUID;


/*
 *@Controller:如果当前类所在的包配置了Spring容器包扫描,具有
 *该注解的类,就会作为bean注册到spring容器中,由spring容器创建实例。
 */
@Controller
@RequestMapping("/show/")
public class WebSocketTestController {

    @Autowired
    private WebSocketService webSocketService;

    /**
     * 跳转thymeleaf模板路径
     *
     * @return
     */
    @RequestMapping("/topic")
    public String websocket() {
        return "topic";
    }

    /**
     * 模拟创建订单,发送消息到客户端
     *
     * @return
     */
    @RequestMapping("/createOrder")
    public @ResponseBody String createOrder() {
        webSocketService.sendMessage("你有新的订单,请及时处理========>" + UUID.randomUUID());
        return "新增订单成功!";
    }
}
  • e、编写html页面

新建一个文件,放到 templates目录下面。页面简单使用js代码调用WebSocket。

页面:topic.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
</head>
<body>
<script type="text/javascript">
    var websocket=null
    if('WebSocket' in window){
        //实现化WebSocket对象,指定要连接的服务器地址与端口  建立连接
        topic=new WebSocket("ws://localhost:8082/websocket");
    }else{
        alert("该浏览器不支持WebSocket!")
    }
	//打开事件
    topic.onopen=function(event){
        console.log("建立连接!");
    }
	//关闭事件
    topic.onclose=function(event){
        console.log("连接关闭!");
    }
	//获得消息事件
    topic.onmessage=function(event){
        console.log("收到消息!"+event.data);
        document.getElementById("info").textContent +=event.data;
        //弹窗提醒
    }
	//发生了错误事件
    topic.onerror=function(){
        alert("websocket发生错误!");
    }
	//浏览器窗口关闭或者刷新事件
    topic.onbeforeunload=function(){
        topic.close();
    }
</script>
<h4>您好</h4>
    <span id="info"></span>
</body>
</html>   
  • f、运行测试

先启动应用,然后在浏览器输入127.0.0.1:8082/show/topic 打开topic.html页面,然后调用127.0.0.1:8082/show/createOrder 模拟数据创建,看页面是否收到创建的数据:

这样就简单实现了服务端实时推送数据到客户端的效果啦!

注意: websocket是全双工的,客户端也可以往服务端推送,两者之间只需要建立一次链接即可!

3)注解介绍

@ServerEndpoint:将目前的类定义成一个websocket服务器端,注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端

@OnOpen:当WebSocket建立连接成功后会触发这个注解修饰的方法。

@OnClose:当WebSocket建立的连接断开后会触发这个注解修饰的方法。

@OnMessage:当客户端发送消息到服务端时,会触发这个注解修改的方法。

@OnError:当WebSocket建立连接时出现异常会触发这个注解修饰的方法。

五、结束语

学不完,根本学不完

本文简单介绍了WebSocket的基本概念,并且用代码演示了一个SpringBoot项目如何接入WebSocket。

其实WebSocket可总结的东西还挺多,比如WebSocket扩展,客户端、服务端之间是如何协商、使用扩展的。WebSocket扩展可以给协议本身增加很多能力和想象空间,比如数据的压缩、加密,以及多路复用等。

相关推荐

JavaScript做个贪吃蛇小游戏(过关-加速),无需网络直接玩。

JavaScript做个贪吃蛇小游戏(过关-则加速)在浏览器打开文件,无需网络直接玩。<!DOCTYPEhtml><htmllang="en"><...

大模型部署加速方法简单总结(大模型 ai)

以下对大模型部署、压缩、加速的方法做一个简单总结,为后续需要备查。llama.cppGithub:https://github.com/ggerganov/llama.cppLLaMA.cpp项...

安徽医大第一医院应用VitaFlow Liberty(R)Flex为患者焕然一“心”

近日,在安徽医科大学第一附属医院心血管内科负责人暨北京安贞医院安徽医院业务副院长喻荣辉教授的鼎力支持和卓越带领下,凭借着先进的VitaFlowLiberty(R)Flex经导管主动脉瓣可回收可...

300 多行代码搞定微信 8.0 的「炸」「裂」特效!

微信8.0更新的一大特色就是支持动画表情,如果发送的消息只有一个内置的表情图标,这个表情会有一段简单的动画,一些特殊的表情还有全屏特效,例如烟花表情有全屏放烟花的特效,炸弹表情有爆炸动画并且消息和...

让div填充屏幕剩余高度的方法(div填充20px)

技术背景在前端开发中,经常会遇到需要让某个div元素填充屏幕剩余高度的需求,比如创建具有固定头部和底部,中间内容区域自适应填充剩余空间的布局。随着CSS技术的发展,有多种方法可以实现这一需求。实现步骤...

css之div内容居中(css中div怎么居中)

div中的内容居中显示,包括水平和垂直2个方向。<html><head><styletype="text/css">...

使用uniapp开发小程序遇到的一些问题及解决方法

1、swiper组件自定义知识点swiper组件的指示点默认是圆圈,想要自己设置指示点,需要获得当前索引,然后赋给当前索引不同的样式,然后在做个动画就可以了。*关键点用change方法,然后通过e.d...

微信小程序主页面排版(怎样设置小程序的排版)

开发小程序的话首先要了解里面的每个文件的作用小程序没有DOM对象,一切基于组件化小程序的四个重要的文件*.js*.wxml--->view结构---->html*.wxss--...

Vue动态组件的实践与原理探究(vue动态组件component原理)

我司有一个工作台搭建产品,允许通过拖拽小部件的方式来搭建一个工作台页面,平台内置了一些常用小部件,另外也允许自行开发小部件上传使用,本文会从实践的角度来介绍其实现原理。ps.本文项目使用VueCLI...

【HarmonyOS Next之旅】兼容JS的类Web开发(四) -> tabs

目录1->创建Tabs2->设置Tabs方向3->设置样式4->显示页签索引5->场景示例编辑1->创建Tabs在pages/index目录...

CSS:前端必会的flex布局,我把布局代码全部展示出来了

进入我的主页,查看更多CSS的分享!首先呢,先去看文档,了解flex是什么,这里不做赘述。当然,可以看下面的代码示例,辅助你理解。一、row将子元素在水平方向进行布局:1.垂直方向靠顶部,水平方向靠...

【HarmonyOS Next之旅】兼容JS的类Web开发(四) -> swiper

目录1->创建Swiper组件2->添加属性3->设置样式4->绑定事件5->场景示例编辑1->创建Swiper组件在pages/index...

CSS:Flex布局,网页排版神器!(css3 flex布局)

还在为网页排版抓狂?别担心,CSS的flex布局来了,让你轻松玩转各种页面布局,实现网页设计自由!什么是Flex布局?Flex布局,也称为弹性布局,是CSS中的一种强大布局方式,它能够让你...

移动WEB开发之flex布局,附携程网首页案例制作

一、flex布局体验传统布局兼容性好布局繁琐局限性,不能再移动端很好的布局1.1flex弹性布局:操作方便,布局极为简单,移动端应用很广泛PC端浏览器支持情况较差IE11或更低版本,不支持或仅部...

2024最新升级–前端内功修炼 5大主流布局系统进阶(mk分享)

2024最新升级–前端内功修炼5大主流布局系统进阶(mk分享)获课》789it.top/14658/前端布局是网页设计中至关重要的一环,它决定了网页的结构和元素的排列方式。随着前端技术的不断发展,现...