Android消息推送 SSE(Server-Sent Events)方案实践

转载请注明出处:https://blog.csdn.net/kong_gu_you_lan/article/details/135777170

本文出自 容华谢后的博客

0.写在前面

最近公司项目用到了消息推送功能,在技术选型的时候想要找一个轻量级的方案,偶然看到一篇文章讲ChatGPT的对话机制是基于SSE来实现的,但是这种协议是基于Web的,客户端能不能用呢,搜索一番发现老朋友OkHttp已经贴心的准备好了一个SSE依赖库,于是便有了这篇文章。

简单介绍下SSE协议,全称Server-Sent Events,2008年首次出现在HTML5规范中,在2014年随着HTML5被W3C推荐为标准,SSE也登上了舞台。作为HTML5的一部分,旨在提供一种简单的机制,用于服务器向客户端推送实时事件数据。

SSE建立在标准的HTTP协议之上,使用普通的HTTP连接,与WebSocket不同的是,SSE是一种单向通信协议,只能是服务器向客户端推送数据,客户端只需要建立连接,而后续的数据推送由服务器单方面完成。

SSE推送流程:

SSE推送流程

1.服务端实现

服务端使用Node.js和Express框架来实现:

const express = require('express');
const http = require('http');
const app = express();
const server = http.createServer(app);// 静态文件目录,发送消息使用
const path = require('path');
app.use(express.static(path.join(__dirname, 'public')));// 用于存储连接的客户端响应对象
const clients = [];// SSE长连接
app.get('/events', (req, res) => {// 设置响应头,指定事件流的Content-Typeres.setHeader('Content-Type', 'text/event-stream; charset=utf-8');res.setHeader('Cache-Control', 'no-cache');res.setHeader('Connection', 'keep-alive');// 发送初始数据res.write('data: SSE 已连接\n\n');// 将客户端的响应对象存储起来clients.push(res);// 当连接断开时从数组中移除响应对象req.on('close', () => {clients.splice(clients.indexOf(res), 1);});
});// 用于接收字符串类型的消息并发送给所有连接的客户端
app.post('/push', express.urlencoded({ extended: true }), (req, res) => {const message = req.body.message;// 向所有连接的客户端发送消息clients.forEach(client => {client.write(`data: 收到消息: ${message},连接数:${clients.length}\n\n`);});res.status(200).send('Message sent successfully');
});const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {console.log(`Server listening on port ${PORT}`);
});

运行命令:

// 初始化项目
npm init -y// 安装Express
npm install express// 启动服务端
node server.js

在服务端中定义了两个接口,/events 接口用于客户端请求的长连接服务,/push 接口用于接收控制台发送的消息,然后转发给已连接的所有客户端。

可以注意到events接口中,和普通接口主要的区别在响应头的设置:

res.setHeader('Content-Type', 'text/event-stream; charset=utf-8');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
  • Content-Type 指定了响应内容的类型为 text/event-stream,表明这是一个SSE响应。

  • Cache-Control 是控制缓存行为的HTTP头部之一。no-cache 意味着客户端不应该缓存响应。由于SSE是基于长连接的实时通信,而不是通过短轮询获得数据,因此不希望客户端缓存响应,以确保每次都能接收到实时的事件数据。

  • Connection 指示服务器保持与客户端的连接处于打开状态。keep-alive 表示持久连接,允许多个请求和响应在单个连接上交替发送,而不必为每个请求都重新建立连接。在SSE中,保持连接的状态使得服务器能够随时向客户端推送事件,而不必反复建立连接,提高了效率。

2.客户端实现

在项目的build.gradle中增加OkHttp的依赖:

dependencies {// OkHttpimplementation("com.squareup.okhttp3:okhttp:4.12.0")implementation("com.squareup.okhttp3:okhttp-sse:4.12.0")
}

OkHttp提供了一个RealEventSource类来实现SSE连接,其中回调了连接、断开、错误和接收消息推送的方法,和普通的OkHttp请求没有太大区别:

val request = Request.Builder().url(binding.etUrl.text.toString()).build()
val okHttpClient = OkHttpClient.Builder().also {it.connectTimeout(1, TimeUnit.DAYS)it.readTimeout(1, TimeUnit.DAYS)
}.build()
val realEventSource = RealEventSource(request, object : EventSourceListener() {override fun onOpen(eventSource: EventSource, response: Response) {super.onOpen(eventSource, response)showMessage("已连接")}override fun onEvent(eventSource: EventSource,id: String?,type: String?,data: String) {super.onEvent(eventSource, id, type, data)showMessage(data)}override fun onClosed(eventSource: EventSource) {super.onClosed(eventSource)showMessage("已断开")}override fun onFailure(eventSource: EventSource,t: Throwable?,response: Response?) {super.onFailure(eventSource, t, response)showMessage("连接失败 ${t?.message}")}
})

3.后台消息推送

有了服务端和客户端,我们再实现一个简单的控制台,用于给已连接的客户端推送消息:

<!DOCTYPE html>
<html lang="ch">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Push</title>
</head>
<body><div><h2>Request:</h2><input type="text" id="messageInput"><button onclick="sendMessage()">发送消息</button></div><div id="responseContainer"><h2>Response:</h2><pre id="responseContent"></pre></div><script>function sendMessage() {const messageInput = document.getElementById('messageInput');const responseContent = document.getElementById('responseContent');// 发送 POST 请求到 /push 接口fetch('/push', {method: 'POST',headers: {'Content-Type': 'application/x-www-form-urlencoded',},body: `message=${encodeURIComponent(messageInput.value)}`,}).then(response => response.text()).then(data => {// 更新页面上的响应内容responseContent.textContent = data;}).catch(error => {console.error('Error:', error);responseContent.textContent = 'An error occurred.';});}</script></body>
</html>

看下效果:

SSE消息推送

不专业的简单测试了下,并发1万个客户端连接,服务端性能并没有什么明细波动,确实比较轻量级。

4.写在最后

GitHub地址:https://github.com/alidili/SSEDemo

到这里,Android消息推送SSE方案就介绍完了,如有问题可以给我留言评论或者在GitHub中提交Issues,谢谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/650227.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

探索半导体制造业中的健永科技RFID读写器的应用方案

一、引言 在当今高度自动化的工业环境中&#xff0c;无线射频识别&#xff08;RFID&#xff09;技术已经成为实现高效生产的重要一环。特别是在半导体制造业中&#xff0c;由于产品的高价值和复杂性&#xff0c;生产过程的追踪和管理显得尤为重要。健永科技RFID读写器以其出色…

Java程序设计实验7 | IO流

*本文是博主对Java各种实验的再整理与详解&#xff0c;除了代码部分和解析部分&#xff0c;一些题目还增加了拓展部分&#xff08;⭐&#xff09;。拓展部分不是实验报告中原有的内容&#xff0c;而是博主本人自己的补充&#xff0c;以方便大家额外学习、参考。 目录 一、实验…

nginx处理跨域问题

内网服务器A&#xff0c;服务映射到外网端口是8080&#xff0c;app接口请求外网8080端口的接口&#xff0c;出现跨域 下面有两种实现配置 server { listen 6600; server_name localhost; root /opt/runner/target/yongxing-one-map-mobile/; access…

【办公技巧】Excel只读模式怎么改成编辑模式?

Excel文件打开之后&#xff0c;大家可能经常会遇到文件处于只读模式的情况&#xff0c;那么我们应该如何将excel只读模式改成编辑模式呢&#xff1f;今天和大家分享几种情况的解决方法。 首先&#xff0c;大部分的只读模式&#xff0c;打开之后都是没有密码的&#xff0c;只是…

LabVIEW振动信号分析

LabVIEW振动信号分析 介绍如何使用LabVIEW软件实现希尔伯特-黄变换&#xff08;Hilbert-Huang Transform, HHT&#xff09;&#xff0c;并将其应用于振动信号分析。HHT是一种用于分析非线性、非平稳信号的强大工具&#xff0c;特别适用于旋转机械等复杂系统的振动分析。开发了…

算法训练营第六十天打卡|84.柱状图中最大的矩形

目录 Leetcode84.柱状图中最大的矩形 Leetcode84.柱状图中最大的矩形 文章链接&#xff1a;代码随想录 文章链接&#xff1a;84.柱状图中最大的矩形 思路&#xff1a;暴力双指针&#xff0c;超时 class Solution { public:int largestRectangleArea(vector<int>& he…

一款强大的矢量图形设计软件:Adobe Illustrator 2023 (AI2023)软件介绍

Adobe Illustrator 2023 (AI2023) 是一款强大的矢量图形设计软件&#xff0c;为设计师提供了无限创意和畅行无阻的设计体验。AI2023具备丰富的功能和工具&#xff0c;让用户可以轻松创建精美的矢量图形、插图、徽标和其他设计作品。 AI2023在界面和用户体验方面进行了全面升级…

2024.1.26 寒假训练记录(9)

今天复习了下差分约束&#xff0c;发现用的是SPFA&#xff0c;这个复杂度…害&#xff0c;明天有空整个板子吧&#xff0c;估计也不太用得上了 花了好长时间搞训练赛的题&#xff0c;明天比赛时间刚好把题解写了&#xff0c;明天再学学网络流好了 文章目录 CF 1798A Showstopp…

单片机学习笔记---矩阵键盘

目录 矩阵键盘的介绍 独立按键和矩阵按键的相同之处&#xff1a; 矩阵按键的扫描 代码演示 代码模块化移植 Keil自定义模板步骤&#xff1a; 代码编写 矩阵键盘就是开发板上右下角的这个模块 这一节的代码是基于上一节讲的LCD1602液晶显示屏驱动代码进行的 矩阵键盘的介…

GPT4.5人工智能即将来临,ChatGPT的正面影响和负面影响(好处和坏处),利弊分析

ChatGPT来了&#xff0c;对我们影响大不大&#xff1f; 近年来&#xff0c;人工智能技术的飞速进步催生了ChatGPT——一种强大的人工智能语言模型。其杰出的生成能力使其能够与人类进行自然、流畅的交流&#xff0c;从而在教育、医疗和娱乐等多个领域展现出巨大的应用潜力。然…

新版UI界面影视小程序亲测无问题带详细搭建教程

新版UI界面影视小程序亲测无问题带详细搭建教程 环境php7.0 — fileinfo–redis–sg11 mysql5.5 apache2.4 添加站点php7.0—-创建ftp—-上传后端文件《后端文件修改&#xff0c;/maccms/wxapi/config/dbs.php–修改当前数据库》—-设置ssl—-打开数据库安装cms 安装好后管…

4. sass实用函数归纳

4. sass实用函数归纳 字符串函数 1、quote(string) 给字符串添加引号 quote(xiaoming) // "xiaoming"2、unquote(string) 移除字符串的引号 unquote("xiaoming") // xiaoming3、str-index(string, substring) 返回 substring 子字符串第一次在 stri…

仰暮计划|“星星之火可以燎原,平凡人的一生同样值得称赞

传递助老之情&#xff0c;践行为老初心。为学习和发扬助老为老精神&#xff0c;我参与了康乐忆享实践队开展的以“仰暮计划”为主题的实践活动&#xff0c;在实践过程中了解老人的人生经历&#xff0c;传播尊老爱老思想。我与老人谭爷爷在谈论家常时&#xff0c;他拿出年轻时的…

【项目日记(五)】第二层: 中心缓存的具体实现(上)

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:项目日记-高并发内存池⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你做项目   &#x1f51d;&#x1f51d; 开发环境: Visual Studio 2022 项目日…

CentOS安装Redis教程-shell脚本一键安装配置

文章目录 前言一、Redis单机版安装教程1. 复制脚本2. 增加执行权限3. 执行脚本 二、Redis扩展集群版安装教程1. 安装Redis单机版2. 复制脚本3. 增加执行权限4. 执行脚本5. 测试6. redis_cluster.sh 命令6.1 启动Redis扩展集群6.2 停止Redis扩展集群6.3 查看Redis扩展集群节点信…

手写rpc和redis

rpc框架搭建 consumer 消费者应用 provider 提供的服务 Provider-common 公共类模块 rpc 架构 service-Registration 服务发现 nacos nacos配置中心 load-balancing 负载均衡 redis-trench 手写redis实现和链接 package com.trench.protocol;import com.trench.enumUtil.Redis…

AI编译器的前端优化策略

背景 工作领域是AI芯片工具链相关&#xff0c;很多相关知识的概念都是跟着项目成长建立起来&#xff0c;但是比较整个技术体系在脑海中都不太系统&#xff0c;比如项目参与中涉及到了很多AI编译器开发相关内容&#xff0c;东西比较零碎&#xff0c;工作中也没有太多时间去做复盘…

Docker容器(自定义镜像,Dockerfile,网桥,DockerCompose)

自定义镜像 镜像就是包含了应用程序、程序运行的系统函数库、运行配置等文件的文件包。构建镜像的过程其实就是把上述文件打包的过程。 构建步骤 镜像结构 Dockerfile 它是一个文本文件&#xff0c;包含很多指令&#xff0c;用指令来说明要执行什么操作来构建镜像。 官网&am…

序列化和反序列化

目录 字节流序列化反序列化区别示例字节流需要注意的问题 字节流 字节流在计算机科学中是一种常见的数据结构&#xff0c;它是一系列字节的序列。字节流通常用来处理输入和输出的数据&#xff0c;例如读写文件、网络通信等。一个字节由8位二进制数字组成&#xff0c;可以代表一…

jQuery HTML - 获取 —— W3school 详解 简单易懂(十一)

jQuery 获得内容和属性 jQuery ChainingjQuery 设置 jQuery 拥有可操作 HTML 元素和属性的强大方法。 jQuery DOM 操作 jQuery 中非常重要的部分&#xff0c;就是操作 DOM 的能力。 jQuery 提供一系列与 DOM 相关的方法&#xff0c;这使访问和操作元素和属性变得很容易。 …