利用socket.io实现消息实时推送

项目背景介绍

最近在写的项目中存在着社交模块,需要实现这样的一个功能:当发生了用户被点赞、评论、关注等操作时,需要由服务器向用户实时地推送一条消息。最终完成的项目地址为:socket-message-push,这里将介绍一下实现的思路及部分代码。

项目的流程中存在着这样的几个对象:

  • 用 Java 实现的后端服务器
  • 用 Node.js 实现的消息推送服务器
  • 用户进行操作的客户端

事件处理的流程如下:

  1. 用户进行点赞操作时,后端服务器会进行处理,并向 Node.js 消息推送服务器发送一条消息
  2. Node.js 消息推送服务器接收到后端发送的消息后,处理数据,并确定向哪个用户进行推送
  3. 用户的客户端接收到由 Node.js 服务器推送来的消息后,即可进行通知的显示。

上面的流程中,Java 后端服务器是如何实现的不在此篇文章的讨论范围内,本文将主要介绍如何使用 Node.js 来实现这个消息推送服务器。

考虑消息推送服务器上必须记录下当前在线用户的信息,这样才能向特定的用户推送消息。所以当用户登录时,必须将自身的用户信息发到 Node.js
服务器上。为了达到这种双向的实时消息传递,很明显地考虑用 WebSocket 来实现。既然我们在消息推送服务器上使用了
Node.js,我们就有了一个很方便的选项:socket.io。

Socket.io 介绍

Socket.io是一个用 JavaScript 实现的实时双向通信的库,利用它来实现我们的功能会很简单。

socket.io 包含两个部分:

  • 服务器端(server):运行在 Node.js 服务器上
  • 客户端(client):运行在浏览器中

可以看看如下的 socket.io 的示例代码,它给出了 socket.io 发出及监听事件的基本用法:


  1. io.on('connection', function(socket){ 
  2.   socket.emit('request', /* */); // emit an event to the socket 
  3.   io.emit('broadcast', /* */); // emit an event to all connected sockets 
  4.   socket.on('reply', function(){ /* */ }); // listen to the event 
  5. });  

关于 Socket.io 还有一点需要注意:Socke.io 并不完全是 WebSocket 的实现。


  1. Note: Socket.IO is not a WebSocket implementation. Although Socket.IO indeed uses WebSocket as a transport when possible, it adds some metadata to each packet: the packet type, the namespace and the ack id when a message acknowledgement is needed. 

接下来我们需要用 Express.js 来建立一个服务器端程序,并在其中引入 Socket.io。

Node.js 服务器的搭建

利用 Express.js 搭建基础服务器

我们使用了 Express.js 来搭建 Node.js 消息推送服务器,先利用一个简要的例子来浏览其功能:


  1. // server.js 
  2. const express = require('express'); 
  3. const app = express(); 
  4. const path = require('path'); 
  5. const http = require('http').Server(app); 
  6.  
  7. const port = 4001; 
  8.  
  9. app.use(express.static(path.join(__dirname, 'public'))); 
  10.  
  11. app.get('/', function(req, res) { 
  12.     res.sendFile(__dirname + '/public/index.html'); 
  13. }); 
  14.  
  15. app.get('/api', function(req, res) { 
  16.     res.send('.'); 
  17. }); 
  18.  
  19. http.listen(port, function() { 
  20.     console.log(`listening on port:${port}`); 
  21. });  

将上面的代码保存为 server.js,新建一个 public 文件夹,在其中放入 index.html 文件。运行以下命令:


  1. node server.js 

现在即可在 localhost:4001 查看效果了。

引入 Socket.io

现在已经有了一个基础的 Express 服务器,接下来需要将 Socket.io 加入其中。


  1. const io = require('socket.io')(http); 
  2.  
  3. io.on('connection', function(socket) { 
  4.     console.log('a user connected'); 
  5.     socket.broadcast.emit('new_user', {}); 
  6. }  

这里的 io 监听 connection 事件,当 client 与 server 建立了连接之后,这里的回调函数会被调用(client 中的代码将在下一节介绍)。

函数的参数 socket 代表的是当前的 client 和 server 间建立的这个连接。可在 client 程序中将这个建立的 socket 连接打印出来,如下图所示:

其中的 id 属性可以用于标识出这一连接,从而 server 可以向特定的用户发送消息。


  1. socket.broadcast.emit('new_user', {}); 

这一行代码表示 socket 将向当前所有与 server 建立了连接的 client(不包括自己) 广播一条名为 new_user 的消息。

后端推送消息的处理流程

  1. 在 Node 服务器建立一个用户信息和 socket id 的映射表,因为同一用户可能打开了多个页面,所以他的 socket id 可能存在多个值。当用户建立连接时,往其中添加值;用户断开连接后,删除相应值。
  2. 当 Java 后台存在需要推送的消息时,会向 Node 服务器的 /api 路径 post 一条消息,其中包括用于标识用户的 tokenId 和其它数据。
  3. Node 服务器接收到 post 请求后,对请求内容进行处理。根据 tokenId 找出与该用户对应的 socket id,socket.io 会根据 id 来向用户推送消息。

对用户信息的处理

方便起见,这里只用一个数组保存用户信息,实际工作中可以根据需要放入数据库中保存。


  1. global.users = []; // 记录下登录用户的tokenId, socketId 

当用户登录时,client 会向 server 发送 user_login 事件,服务器接收到后会做如下操作:


  1. socket.on('user_login', function(info) { 
  2.     const { tokenId, userId, socketId } = info; 
  3.     addSocketId(users, { tokenId, socketId, userId }); 
  4. });  

addSocketId() 会向 users 数组中添加用户信息,不同用户通过 tokenId 进行区分,每个用户有一个 socketIds 数组,保存可能存在的多个 socketId。该函数的具体代码可见 src/utils.js 文件。

同理,还有一个 deleteSocketId() 函数用于删除用户信息,代码可见同一文件。

在获取了用户的 tokenId 之后,就需要找到对应的 socketId,然后向特定用户推送消息。


  1. // 只向 id = socketId 的这一连接发送消息  
  2. io.sockets.to(socketId).emit('receive_message', { 
  3.     entityType, 
  4.     data 
  5. });  

服务器的思路大致如此,接下来介绍客户端中是如何进行相应的处理的。

客户端

Socket.io 的初始化

首先在 html 文件中引入 Socket.io 的 client 端文件,例如通过 CDN 引入:


  1. <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script> 

其它的引入方式:


  1. <script src="/socket.io/socket.io.js"></script> 

  1. const io = require('socket.io-client'); 
  2.  
  3. // or with import syntax 
  4.  
  5. import io from 'socket.io-client';  

引入 Socket.io 后就获得了 io 函数,通过它来与消息推送服务器建立连接。


  1. // 假设你将 Node 服务器部署后的地址为:https://www.example.com/ws 
  2. // 则: WS_HOST = 'https://www.example.com' 
  3. const msgSocket = io(`${WS_HOST}`, { 
  4.     secure: true, 
  5.     path: '/ws/socket.io' 
  6. });  

如果监听本地:


  1. const msgSocket = io('http://localhost:4001'); 

这里如果写成 io('https://www.example.com/ws') 会出现错误,需要将 /ws 写入path中。

为了能在其它文件使用这一变量,可将 msgSocket 作为一个全局变量:


  1. window.msgSocket = msgSocket; 

用户建立连接


  1. // 用户登录时,向服务器发送用户的信息。服务器会在收到信息后建立 socket 与用户的映射。 
  2. msgSocket.emit('user_login', { 
  3.     userId, 
  4.     socketId: msgSocket.id, 
  5.     tokenId 
  6. });  

接收到推送的消息后的处理


  1. // WebSocket 连接建立后,监听名为 receive_message 的事件  
  2. msgSocket.on('receive_message', msg => { 
  3.     store.dispatch({ 
  4.         type: 'NEW_SOCKET_MSG', 
  5.         payload: msg 
  6.     }); 
  7. }); 

当 WebSocket 服务器向客户端推送了消息之后,客户端需要监听 receive_message 事件,接收到的参数中有相应待处理的信息。

由于使用了 Redux 进行数据的处理,所以这里 dispatch 了一个 NEW_SOCKET_MSG action,后续则是常规的 redux 处理流程了。

项目的使用

GitHub 上的项目地址:socket-message-push


  1. npm run dev 

即可在 devlopment 环境下进行测试,现在你就有了一个运行在4001端口的消息推送服务器了。

但是这里并没有后端的服务器来向我们发送消息,所以我们将利用 Postman 来模拟发送消息。

为了展示程序的功能,在项目的 client 文件夹下放置了一个 index.html 文件。注意这个文件并不能用在实际的项目中,只是用来显示消息推送的效果而已。

在开启了服务器之后,打开 client/index.html,根据提示随意输入一个 tokenId 即可。

现在利用 Postman 向 localhost:4001/api post 如下的一条信息:


  1. {  
  2.     // tokens 数组表示你想向哪个用户推送消息 
  3.     "tokens": ["1", "2"],  
  4.     "data": "You shall not pass!!!" 

至此,如果一切顺利,你应该能够在 client 的控制台中看到收到的消息了。

你可以打开多个 client 页面,输入不同的 tokenId,然后检查消息是否发送给了正确的用户。

作者:noiron

来源:51CTO

时间: 2024-10-31 22:30:30

利用socket.io实现消息实时推送的相关文章

signalR 实现数据库实时推送数据

问题描述 signalR 实现数据库实时推送数据 软件:VS2015/MSSQL2014问题:为什么下图的前端显示内容 传表就可以 而像我传num的一个数就不行了?? 解决方案 传一个数字也可以,但是你的js的json解析的代码需要修改,不能for循环. 解决方案二: socket实现数据库数据实时推送到服务器

Web 实时推送技术的总结

随着 Web 的发展,用户对于 Web 的实时的要求也越来越高 ,比如,工业运行监控.Web 在线通讯.即时报价系统.在线游戏等,都需要将后台发生的变化主动地.实时地传送到浏览器端,而不需要用户手动地刷新页面.本文对过去和现在流行的 Web 实时推送技术进行了全面的总结. 在标准的 HTTP 请求-响应的情况下,客户端打开一个连接,发送一个 HTTP请求(例如 HTTP GET 请求)到服务端,然后接收到 HTTP 回来的响应,一旦这个响应完全被发送或者接收,服务端就关闭连接.当客户端需要请求所

百度实时推送api接口应用示例_php实例

网站质量不错的网站可以在百度站长平台/数据提交/sitemap栏目下看到实时推送的功能, 目前这个工具是邀请开放, 百度的实时推送的api接口可以实时推送我们新发布的文章, 保证百度在第一时间收录.   百度站长平台 http://zhanzhang.baidu.com/ 打开百度站长平台, 点开实时推送的添加新数据接口获得带token的api推送地址:     http://ping.baidu.com/sitemap?site=www.yourdomain.com&resource_name

第一时间实时推送新片 电驴大全登陆iPhone客户端

国内知名资源分享类网站VeryCD最新发布影视类在线观看客户端--电驴影视大全iPhone版,汇集了国内 主流视频网站的高清优秀资源,囊括电影.剧集.综艺.动漫等当下最热门的渠道,并结合VeryCD社区内百万用户交流汇集的影视资料与影评,为用户提供不同凡响的娱乐体验.电驴推出iPhone版影视大全知名P2P资源分享类网站VeryCD自从 版权问题所引发的争议开始,转而改向影视资源在线观看.乐园.在线网页游戏等 多维度发展,特别是在线高清正版影视做的风生水起,其资源汇集了优酷.土豆.搜狐.奇艺.酷

ajax-AJAX轮询机制,消息及时推送怎么实现?

问题描述 AJAX轮询机制,消息及时推送怎么实现? 我主要想问问,我们买家登录像京东天猫这样的网站上面有买家几条消息未读, 或是邮件上面的几封信息未读等这样显示是怎么实现的?是用得消息推送机制吗? 还是买家登录后去数据库查询了一次,然后现在出来的?懂的大神求解!?谢谢. 解决方案 websocket push机制.

IOS-群组消息离线推送显示问题

问题描述 群组消息离线推送,只显示了发消息的人,并没有显示来自哪个群组?请问如何解决? 解决方案 环信离线推送的alert好像是可以自定义显示的,发送的时候在扩展里加一个字段,具体的你可以看看他们的文档.通过扩展自定义显示,应该可以实现你的需求.

seo-请教,asp.net如何实现百度sitemap实时推送

问题描述 请教,asp.net如何实现百度sitemap实时推送 比如我后台发了一条咨询,能在发布后马上调用sitemap让百度收录新发布的页面内容 解决方案 百度什么时候收录,这个百度说了算,百度可不会按照你的愿望随时收录.

百度实时推送POST推送怎么用啊

问题描述 百度实时推送POST推送怎么用啊要写方法吗?怎么执行啊? 解决方案 本帖最后由 u014709884 于 2015-04-25 12:02:27 编辑解决方案二:捉鸡啊来个大神回答下吧解决方案三:人家说的是主动推送不是实时推送你若要实时就是有新页面了调用下他这页面填下参数解决方案四:同问,我也着急想知道解决方案五:同问实时提交的用法啊,哪位大神知道啊!解决方案六:私聊我我可以给源码解决方案七:http://pan.baidu.com/s/1dDMknst下载即可

wordpress更新文章实时推送到百度教程

百度最近在站长平台里发布了公告,决定停用现在的百度sitemap1.0,使用了新的推送方式,也就是今天的主角:主动推送(实时). 文章实时推送到百度教程-wordpress 实时推送"> 那么先前安装的wordpress插件也可以卸载了,申请了百度实时推送的接口. 首先给出申请地址:http://zhanzhang.baidu.com/linksubmit/ 大家前去了解下百度新的主动推送机制! 然后,结合本站团队成员维维大神的研究测试,且免去安装WP BaiDu Submit插件的实现了