进度变动实时通知-使用SocketIO实现前后端的通信(基于WebSocket的实时通信库)

这篇具有很好参考价值的文章主要介绍了进度变动实时通知-使用SocketIO实现前后端的通信(基于WebSocket的实时通信库)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

最近在接触的一个项目,将PDF上传到项目里,通过调用OCR云服务把PDF里的表格数据识别出来。在此过程中,前后端需要实时通信,对识别数据进行“进度跟踪”。因此我们采用SocketIO的通讯方式,识别中前端和后端服务建立SocketIO连接,根据事件进行数据的实时更新百分比进度,并且显示在页面中。

简介

SocketIO是在客户端和服务端之间建立的双向通信数据交换技术,它可以在客户端和服务器之间实现低延迟、双向和基于事件的通信。

SocketIO建立在WebSocket协议之上,WebSocket仍然可能纯在浏览器不兼容的情况,但SocketIO无需担心兼容问题,底层会自动选用最佳的通信方式。例如回退到 HTTP 长轮询或自动重新连接。

工作原理

当一个浏览器尝试建立SocketIO时,SocketIO首先使用xhr-polling创建一个长轮询。长轮询一旦建立,它将升级为WebSocket连接。

客户端

SocketIO通过一个XHR(XMLHttprequest)握手,前端发送一个XHR,告诉服务器我要开始长轮询你了~
握手是通过一个HTTP Upgrade request开始的,一个请求头部分示例如下:

    ###### Request Headers ######
    Connection: Upgrade
    Host: ip:SocketIO监听的端口
    Origin: http://sockert.io.demo.com
    Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits
    Sec-WebSocket-Key: bz69CkdvaPHtOTEshtmWvw==
    Sec-WebSocket-Version: 13
    Upgrade: websocket

1. Upgrade 是HTTP/1.1中规定的用于转换当前连接的应用层协议的头部,表示客户端希望用现有的连接转换到新的应用层协议WebSocket协议
2. Origin 用于防止跨站攻击,浏览器一般会使用这个来标识原始域,对于非浏览器的客户端应用可以根据需要使用。
3. 请求头中的 Sec-WebSocket-Version 是WebSocket版本号,Sec-WebSocket-Key 是用于握手的密钥

前端发送完一个XHR后,后端返回的数据如下:

    0{"pingInterval":25000,
      "pingTimeout":60000,
      "upgrades":["websocket"],
      "sid":"9c54f9c1759c4dbab8f3ce20c1fe43a4"
      }40


1. sid是本次SocketIO的会话ID,因为一次SocketIO包含了多个请求,而后端又会同时连接多个SocketIO,sid的作用就相当于SESSIONID。
2. 另一个字段upgrades,正常情况下是 [‘websocket’],表示可以把连接方式从长轮询升级到WebSocket。

前端收到后端返回的upgrades后,SocketIO会检测浏览器是否支持WebSocket,如果支持,就会启动一个**WebSocket**连接,然后通过这个WebSocket往服务器发一条内容为 probe, 类型为ping的数据。如果这时服务器返回了内容为probe,类型为pong的数据,前端就会把前面建立的HTTP长轮询停掉,后面只使用WebSocket通道进行收发数据。

进度变动实时通知-使用SocketIO实现前后端的通信(基于WebSocket的实时通信库)

 

绿色发送,白色接收。前面的数字表示数据包类型,2是ping,3是pong。
其中“42”,4是message类型标识,2是socket.io的EVENT类型标识,而后面则是事件名称和数据,数据可以是字符串,字典,列表等类型。

SocketIO生命周期内,会间隔一段时间ping-pong一次,检测连接是否中断。
进度变动实时通知-使用SocketIO实现前后端的通信(基于WebSocket的实时通信库)

 

 SpringBoot + vue-socket.io 实现双向数据通信

常用的方式是前端使用SocketIO,后端使用node.js实现SocketIO的接口。但由于目前服务端使用JAVA,所以我使用的是Netty-SocketIO开源库,基于Netty网络库编写的WebSocket实现。

服务端

pom

<dependency>
    <groupId>com.corundumstudio.socketio</groupId>
    <artifactId>netty-socketio</artifactId>
    <version>1.7.19</version>
</dependency>

SocketIO配置示例

@Configuration
public class SocketIOConfig {

    @Bean
    public SocketIOServer socketIoServer(PdfConfigurationProperties properties) {
        SocketConfig socketConfig = new SocketConfig();
        //socketConfig.setTcpNoDelay(false);
        //socketConfig.setSoLinger(0);
        com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();
        config.setSocketConfig(socketConfig);
        config.setHostname(properties.getSocketIo().getHost());
        config.setPort(properties.getSocketIo().getPort());
        config.setContext(properties.getSocketIo().getContext());
        // socket连接数大小(如只监听一个端口boss线程组为1即可)
       config.setBossThreads(properties.getSocketIo().getBossCount());
        config.setAllowCustomRequests(properties.getSocketIo()
        .isAllowCustomRequests());
        // 协议升级超时时间(毫秒),默认10秒。
        //config.setUpgradeTimeout(properties.getSocketIo()
        //.getUpgradeTimeout());
        // Ping消息超时时间(毫秒),默认60秒
        //config.setPingTimeout(properties
        //.getSocketIo().getPingTimeout());
        // Ping消息间隔(毫秒),默认25秒。
        //config.setPingInterval(properties
        //.getSocketIo().getPingInterval());
        return new SocketIOServer(config);
    }
    
    @Bean
    public SpringAnnotationScanner springAnnotationScanner(SocketIOServer socketServer) {
        return new SpringAnnotationScanner(socketServer);
    }
}

消息处理代码示例(用于前后的消息交互)

     /**
     * 接受事件消息
     * 识别进度
     *
     * @param client  客户端
     * @param request 请求
     * @param ids     数据
     */
    @OnEvent(PUSH_DATA_EVENT)
    public void pushDataEvent(SocketIOClient client, AckRequest request, String... ids) {
        removeSession(sessionId(client), IDENTIFY_MAP);
        for (String id : ids) {
            updateMap(IDENTIFY_MAP, id, client);
        }
        publishEvent(client, PUSH_DATA_EVENT, request, ids);
    }


    /**
     * 推送统计信息
     */
    @OnEvent(Constants.PUSH_IDENTIFY_MESSAGE)
    public void statistics(SocketIOClient client, AckRequest request, String bh) {
        if (StringUtils.isNotBlank(bh)) {
            publishEvent(client, Constants.PUSH_IDENTIFY_MESSAGE, request, bh);
        }
        publishEvent(client, Constants.PUSH_IDENTIFY_MESSAGE, request);
    }
     
    private void publishEvent(SocketIOClient client, String event, AckRequest request, String... ids) {
        SocketInteract interact = new SocketInteract(sessionId(client), event, ids);
        context.publishEvent(interact);
    }
    
    /**
     * 向前端发送消息
     */
     
     public void sendMessage(String sessionId) {
        SocketIOClient client = CLIENT_MAP.get(sessionId);
        if (client != null) {
            client.sendEvent(Constants.PUSH_IDENTIFY_MESSAGE);
        }
    }

通过SpringBoot的事务监听器@TransactionalEventListener处理接收到数据后的相关业务逻辑。

@Component
@Slf4j
@RequiredArgsConstructor
public class SocketListener {

    private final SocketService socketService;

    @Async
    @TransactionalEventListener(fallbackExecution = true)
    public void handlerUploadFinished(SocketInteract interact) {
        // 调用scoketService查询数据
        socketService.process(interact);
    }


    /**
     * 识别进度
     * @param event 事件
     */
    @Async
    @TransactionalEventListener(fallbackExecution = true)
    public void handlerPictureOcrFinished(PictureOcrFinishedEvent event) {
        // 调用scoketService查询数据
        PictureOcrTask task = (PictureOcrTask) event.getSource();
        log.debug("文件编号:{}识别进度,总数:{},进度:{}", task.getPdfBh(), task.getPdfPageSize(), task.getCurrentPage());
        socketService.process(new SocketInteract(Constants.PUSH_DATA_EVENT, task.getPdfBh()));
    }
}

客户端(浏览器)

客户端建立连接,发送消息示例代码
1. 引入vue-socket.io插件
2. 进入vue项目src文件夹下main.js添加下方代码

import VueSocketIO from 'vue-socket.io'
Vue.use(new VueSocketIO({
  debug: true,
  connection: 'http://socketAdress',  //
  vuex: {
    store,
    actionPrefix: 'SOCKET_',
    mutationPrefix: 'SOCKET_'
  },
}));

3. 前端实现数据传输

//将json发送给服务端,message事件 实现数据交互
  this.$socket.$emit('getUser', this.currentUser);
// 建立连接
  this.$socket.emit('push_dataItem_event', fileItem);

总结

使用SocketIO长连接的特性,无需短轮询频繁建立连接,做进度变动并且实现消息及时通知还是很nice的!
 文章来源地址https://www.toymoban.com/news/detail-463706.html

到了这里,关于进度变动实时通知-使用SocketIO实现前后端的通信(基于WebSocket的实时通信库)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • node笔记_express结合formidable实现前后端的文件上传

    大家好,我是yma16,本期分享node

    2024年02月05日
    浏览(27)
  • 实时消息传送:WebSocket实现系统后台消息实时通知

    在现代Web应用中,提供实时通知对于改善用户体验至关重要。WebSocket技术允许建立双向通信通道,从系统后台将消息实时传送给系统用户,并在前端以弹窗的形式通知用户。本文将深入探讨如何使用WebSocket来实现这一功能。 WebSocket是一种双向通信协议,与传统的HTTP通信不同

    2024年02月08日
    浏览(36)
  • 【前后端的那些事】15min快速实现图片上传,预览功能(ElementPlus+Springboot)

    前言 :最近写项目,发现了一些很有意思的功能,想写文章,录视频把这些内容记录下。但这些功能太零碎,如果为每个功能都单独搭建一个项目,这明显不合适。于是我想,就搭建一个项目,把那些我想将的小功能全部整合到一起。实现 搭一次环境 ,处处使用。 本文主要

    2024年01月19日
    浏览(35)
  • 学习node之——如何在项目中使用MySQL、前后端的身份认证

    上一篇文章只写了一丢丢,这篇才是正片,look look look 这里连接数据库的用户和密码都是我们在安装mysql时配置的密码。每个人的users表格里面数据不同,结果也会不一样哟! 巧2小黑板啦!这里有两个知识点: 1、可以通过英文?符号占位符指定具体的值 2、用insert into插入数

    2024年02月10日
    浏览(31)
  • 基于vue+websocket实现web端的实时pcm音频播放

    pcm-player是一个JavaScript库,用于在浏览器中播放PCM音频文件。PCM是一种数字音频编码格式,它将模拟音频信号转换为数字信号。在Vue中使用PCMPlayer可以让你在Web应用中轻松处理音频播放。 安装pcm-player 在Vue组件中引入PCMPlayer 在你的Vue组件中,你需要引入PCMPlayer库。你可以在组

    2024年04月09日
    浏览(70)
  • SpringBoot使用SSE进行实时通知前端

    项目有个需求是要实时通知前端,告诉前端这个任务加载好了。然后想了2个方案,一种是用websocket进行长连接,一种是使用SSE(Sever Send Event),是HTTP协议中的一种,Content-Type为text/event-stream,能够保持长连接。 websocket是前端既能向后端发送消息,后端也能向前端发送消息。

    2024年02月08日
    浏览(41)
  • flask socketio 实时传值至html上【需补充实例】

    跨域问题网上的普通方法无法解决。 参考这篇文章解决 Flask教程(十九)SocketIO - 迷途小书童的Note迷途小书童的Note (xugaoxiang.com) 如果用了eventlet,在while true中,emit数据不在前端web页面显示,可参考这篇文章的解决方案,加定时器。 javascript - Flask-websocket Emit主动发送消息失败

    2024年02月07日
    浏览(29)
  • WebSocket实现后端数据变化,通知前端实时更新数据

    背景 ​ 项目中需要做一个消息提示功能,当有用户处理相关待办信息后,别的用户需要实时更新处理后的待办信息。 解决方案: ​ 1、使用最原始的方法,写个定时器去查询待办信息。但这种方式在大多数情况是不被允许的,它会浪费系统中的许多资源,同时也并不是完全

    2024年04月15日
    浏览(38)
  • iOS开发-NotificationServiceExtension实现实时音视频呼叫通知响铃与震动

    iOS开发-NotificationServiceExtension实现实时音视频呼叫通知响铃与震动 在之前的开发中,遇到了实时音视频呼叫通知,当App未打开或者App在后台时候,需要通知到用户,用户点击通知栏后是否接入实时音视频的视频或者音频通话。 在iOS需要为工程新建Target:NotificationServiceExtensi

    2024年02月14日
    浏览(34)
  • flask框架-[实现websocket]:将socketio处理函数部分集中管理,使用类的方式来管理,集中管理socketio处理函数

    注意:在flask2.x版本依赖,不再支持flask_script了 flask2.x版本会自动注册 flask run 和flask db 两个命令行命令 1、启动项目 flask run --host 0.0.0.0 --port 9000 2、数据库迁移命令 flask db init flask db migrate flask db upgrade apps         __init__.py  : 创建app应用,各种注册         websocket   

    2024年02月07日
    浏览(38)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包