iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >nodejs+socket.io实现p2p消息实时发送的项目实践
  • 832
分享到

nodejs+socket.io实现p2p消息实时发送的项目实践

2024-04-02 19:04:59 832人浏览 独家记忆
摘要

目录常见的消息通知:实现思路与步骤等其他方法介绍技术实现与相关包介绍包介绍技术实现服务端客户端常见的消息通知: 常见的站内通知类别(括号里是对自己目前项目出现情况的分析,读者忽略):

常见的消息通知:

常见的站内通知类别(括号里是对自己目前项目出现情况的分析,读者忽略):

  • 公告 Announcement (通道加入新的组织、某组织或用户新上传了某数据摘要、系统凌晨需要版本更新等事件)
  • 提醒 Remind(用户之间、系统与用户之间)
    • 资源订阅提醒(关注的数据摘要更新了内容、评论等)
    • 资源发布提醒(我发布的数据摘要被评论了,被关注了,被申请交易了)
    • 系统提醒
  • 私信 Mailbox(类似聊天室吧,暂时没有这需求)

实现思路与步骤等

除了用消息队列MQ以外,笔者想到的是使用websocket协议实现,该协议为全双工通信full-duplex,长连接PersistentConnection,相比Http来说是种持久化协议。

其中主要的开发步骤有:

  • 绑定连接(用户账号和WEBSocket之间的连接)
  • 管理连接
  • 收发消息(数据格式和读取等具体实现)。

其中,需要注意的点有:

  • 长连接的心跳激活处理;
  • 服务端调优实现高并发量client同时在线(单机服务器可以实现百万并发长连接);
  • 群发消息;
  • 服务端维持多用户的状态;
  • 从WebSocket中获取httpsession进行用户相关操作等

具体实现思路:

  • 前端使用WebSocket与服务端创建连接的时候,将用户ID传给服务端,服务端将用户ID与channel关联起来存储,同时将channel放入到channel组中。(这里的channel就是服务器与客户端之间的连接)
  • 如果需要给所有用户发送消息,直接执行channel组的writeAndFlush()方法;
  • 如果需要给指定用户发送消息,根据用户ID查询到对应的channel,然后执行writeAndFlush()方法;
  • 前端获取到服务端推送的消息之后,将消息内容展示到文本域中。

其他方法介绍

轮询:客户端定时向服务器发送ajax请求,服务器接到请求后马上返回响应信息并关闭连接。 优点:后端程序编写比较容易。 缺点:请求中有大半是无用,浪费带宽和服务器资源。 实例:适于小型应用。

长轮询:客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求。 优点:在无消息的情况下不会频繁的请求,耗费资小。 缺点:服务器hold连接会消耗资源,返回数据顺序无保证,难于管理维护。 Comet异步的ashx, 实例:WebQQ、Hi网页版、Facebook IM。

长连接:在页面里嵌入一个隐蔵iframe,将这个隐蔵iframe的src属性设为对一个长连接的请求或是采用xhr请求,服务器端就能源源不断地往客户端输入数据。 优点:消息即时到达,不发无用请求;管理起来也相对便。 缺点:服务器维护一个长连接会增加开销。 实例:Gmail聊天

Flash Socket:在页面中内嵌入一个使用了Socket类的 Flash 程序javascript通过调用此Flash程序提供的Socket接口与服务器端的Socket接口进行通信,JavaScript在收到服务器端传送的信息后控制页面的显示。 优点:实现真正的即时通信,而不是伪即时。 缺点:客户端必须安装Flash插件;非HTTP协议,无法自动穿越防火墙。 实例:网络互动游戏。

技术实现与相关包介绍

包介绍

nodejs不像其他的服务器,对于不同的连接,不支持进程和线程操作,写这类功能的时候就需要找更合适的包。

使用WebSocket协议的包有好多,这里我先讲一种常用的包是nodejs-websocket包,网评说使用较为繁琐,这里就没使用。它需要依赖于底层的c++,python的环境,支持以node做客户端的访问。当然了,这里我一定要说一下,nodejs-websocket是纯粹的使用了WebSocket协议,因此使用时需要写心跳检测,检测用户是否在线等情况。

我采用的是socket.io,它使用起来较为简单,功能强大,支持集成websocket服务器端和Express3框架与一身。它可以不需要心跳检测,不过这也是个相对说法,因为它结合封装了轮询机制和实时通信,当websocket连接断掉时,它会不停的尝试连接,耗费资源。当然了,还有其他库,比如node-websocket-server(不需要了解,直接放弃)。

技术实现

在实现前,考虑到发送消息时,向指定用户发送WebSocket消息,但对方可能不在线,这种情况,我这么处理:

  • 如果接收者在线,则存储进Redis并实时发送消息;
  • 否则将消息存储到redis,等用户登陆上线后主动推送未读消息。

socket.io的客户端和服务端都有两个函数 on()、emit(),核心函数,可轻松实现客户端与服务端的双向通信。

  • emit:触发一个事件,第一个参数是事件名称,第二个参数是要发送到另一端的数据,第三个参数是一个回调函数用来确认对方的接收信息(也可以说时回执),可忽略。
    • socket.emit 信息传输对象为当前 socket 对应的 client ,各个client socket 相互不影响。
    • socket.broadcast.emit 信息传输对象为所有 client ,排除当前socket 对应的 client。
    • io.sockets.emit信息传输对象为所有 client。
  • on:注册一个事件,用来监听 emit 触发的事件。

服务端

直接上代码:

    'use strict';

    // 维护socket连接的代码
    const { addSocketId, getSocketId, deleteSocketId } = require('../../../utils/socket/socketId');
    // 保存消息
    const message = require('../saveMessage');
    // socket连接许可验证
    const { socketAuth } = require('../../../middleware/socket/index')

    // socket接口,传入/bin/www.js
    function init(io) {
    
        
    io.use((socket, next) => {
        if (socket.request.headers.cookie) return next();
        next(new Error('Authentication error'));
    });

    io.on('connection', function(socket) {

                
        socket.on('user_login', function(socketInfo) {       
            if(!socketInfo.userId) {
                // io.sockets.to(socketInfo['socketId']).emit('disconnect', '');
                return;
            }
            // 将用户与socket插入数据库中
            addSocketId(socketInfo);  
                      
            if (process.env.NODE_ENV === 'development') {
                displayUserInfo(socketInfo);
            };

            // 推送所有消息
            message.pushMessage(socketInfo['userId']).then(pushData => {
                io.sockets.to(socketInfo['socketId']).emit('push_message', pushData);
            });
        });
    
                
        socket.on('todo', function(todoData) {    
            // 存入redis
            message.addMessage(todoData);
            // 检测用户是否在线
            message.isOnline(todoData['receiver_id']).then(isOnline => {
                // 用户在线则通信
                if (isOnline == true) {
                    getSocketId(todoData['receiver_id']).then(socketId => {            
                        io.sockets.to(socketId).emit('todo_message', todoData);
                    }); 
                };  
            });
        });
    
        // TODO: 需要提醒前端在关闭窗口之前先断开连接(窗口刷新之前应该不需要)
                
        socket.on('disconnect', function() {
            // 从数据库中删除连接
            deleteSocketId(socket.id);
            // 判断当前是否是开发环境
            if (process.env.NODE_ENV === 'development') {
                displayUserInfo();
            }
        });
    
    });
    
}

function displayUserInfo(user) {
    console.log(`当前登录用户信息:${user}`);
    return;
}

module.exports = {
    init
};

上方代码中,主要创建了connection事件,其下又有user_login、todo、disconnect事件,然后这些事件下又有其创建或监听的事件。其中,user_login事件主要是监听前端用户的登录成功,若用户成功上线,则将redis内的已读未读消息分类后推送给客户端。todo事件则是判断用户在线后,实时传递消息,需要注意使用io.sockets.to(socketId).emit(eventname, eventdata)实现P2P消息传送,socketId即为接收消息用户的WebSocket连接的ID。客户端则需要监听后面emit()参数中的eventname事件。disconnect事件则是在客户端用户登出或刷新页面等认为是断开WebSocket连接时,在维护的socket连接组中删除该用户的WebSocket连接信息。

当然,在连接到connection事件前,有一个中间件io.use((socket, next) => {},是判断对方的连接是否有效(带有cookie的主动连接)。

然后,在/bin/www .js中引入io:

#!/usr/bin/env node

// 模块依赖
var app = require('../app');
var http = require('http');
const socketIndex = require('../src/routes/socket/index/socket');

// 从环境中取端口,应用到express
var port = nORMalizePort(process.env.PORT || '3000');
app.set('port', port);

// 创建http服务(将express注册到http中)
server = http.createServer(app);

// 监听
var io = require('socket.io')(server, {
  cors: {
      origin: '*'
  }
  // path: '/socket' // 重新定义socket连接路径
});

// 全局声明
global.io = io;

// socket的程序文件下引入io
socketIndex.init(io);

其中,引入函数init()即是上一段代码中的init函数,传入参数即为在服务端入口中创建的io服务。io服务中需要传入cors参数,解决跨域问题,如果想更改websocket连接的地址,则使用path参数,其参数值即是在原先基础的websocket连接地址后加上。

客户端

首先创建一个socket对象,io() 的第一个参数是链接服务器的 URL,默认情况下是 window.location(需要修改成服务端的URL,包括对应的模块或权限对应的指定路径,path参数)。

到此这篇关于nodejs+socket.io实现p2p消息实时发送的项目实践的文章就介绍到这了,更多相关node socket.io实现p2p实时发送内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: nodejs+socket.io实现p2p消息实时发送的项目实践

本文链接: https://www.lsjlt.com/news/151003.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • nodejs+socket.io实现p2p消息实时发送的项目实践
    目录常见的消息通知:实现思路与步骤等其他方法介绍技术实现与相关包介绍包介绍技术实现服务端客户端常见的消息通知: 常见的站内通知类别(括号里是对自己目前项目出现情况的分析,读者忽略):...
    99+
    2024-04-02
  • 利用Socket.io 实现消息实时推送功能
    项目背景介绍最近在写的项目中存在着社交模块,需要实现这样的一个功能:当发生了用户被点赞、评论、关注等操作时,需要由服务器向用户实时地推送一条消息。最终完成的项目地址为:https://github.com/noiron/socket-mes...
    99+
    2023-05-30
    socket.io 消息 推送
  • 如何使用socket.io实现消息实时推送功能
    本篇文章给大家分享的是有关如何使用socket.io实现消息实时推送功能,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Socket.io 介绍...
    99+
    2024-04-02
  • python实现定时发送qq消息
    因为生活中老是忘记各种事情,刚好又在学python,便突发奇想通过python实现提醒任务的功能(尽管TIM有定时功能),也可定时给好友、群、讨论组发送qq消息。其工作流程是:访问数据库提取最近计划——>根据数据内容(提醒时间、提醒...
    99+
    2023-01-31
    消息 python qq
  • SpringBoot项目实现短信发送接口开发的实践
    一. 短信接口实现 描述:请求第三方短信接口平台(而第三方短信平台的接口请求是webservice方式实现的),此时我们要测试接口是否通,要用的工具SoapUI测试工具, 不能用P...
    99+
    2024-04-02
  • 如何在PHP项目中实现实时消息推送和WebSocket支持?
    如何在PHP项目中实现实时消息推送和WebSocket支持?随着互联网的发展,实时消息推送和WebSocket成为了现代web应用中不可或缺的功能。实时消息推送能够实现及时通知和消息传递,提高用户体验,而WebSocket可以用于实现实时双...
    99+
    2023-11-02
    websocket 推送 实时消息
  • SpringBoot小程序推送信息的项目实践
    目录1.小程序推送信息列如我们去餐厅等位有预约提醒,剩余桌数2.申请小程序信息,申请信息模板3.根据开发文档开发4.代码如下:5.推送结果1.小程序推送信息列如我们去餐厅等位有预约提...
    99+
    2024-04-02
  • redisstream实现消息队列的实践
    目录redis 实现消息对列4中方法发布订阅list 队列zset 队列Stream 队列基本命令xadd 生产消息读取消息xgroup 消费者组xreadgroup 消费消息Pen...
    99+
    2022-11-13
    redis stream 消息队列 redis 消息队列
  • 前端与RabbitMQ实时消息推送怎么实现
    这篇文章主要讲解了“前端与RabbitMQ实时消息推送怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“前端与RabbitMQ实时消息推送怎么实现”吧!web 端实时消息推送,常用的实现...
    99+
    2023-06-27
  • java实现web实时消息推送的七种方案
    目录引言什么是消息推送(push)短轮询长轮询iframe流SSE (我的方式)MQTTWebsocket自定义推送Github地址引言 做了一个小破站,现在要实现一个站内信web消...
    99+
    2024-04-02
  • PHP实现即时通讯聊天消息发送功能
    随着互联网的不断发展,即时通讯已经成为现代社会日常沟通的主要形式,因此实现即时通讯聊天消息发送功能成为了各个网站和应用程序的必备特性。本文将介绍PHP实现即时通讯聊天消息发送功能的步骤和注意事项。一、数据库创建首先,我们需要创建一个数据库来...
    99+
    2023-05-22
    PHP 实时通讯 消息发送
  • PHP和WebSocket: 实现实时消息推送的高效方案
    PHP和WebSocket: 实现实时消息推送的高效方案在Web应用程序中,实时消息推送是一项常见的需求。传统的基于HTTP协议的请求-响应模式无法满足实时性要求,因此需要采用其他技术来实现实时消息推送。WebSocket是一种能够在浏览器...
    99+
    2023-12-18
    PHP websocket 实时消息推送 关键词:
  • Python实现向好友发送微信消息
    目录前言c语言发微信消息Python调用不用c编写dll如何发消息调用我们写入的机器码第一次优化第二次优化x86/x64 Call Jmp指令区别前言 原理:Windows逆向,通过...
    99+
    2024-04-02
  • java发送kafka事务消息的实现方法
    前言 事务对java开发的同学来说并不陌生,我们使用事务的目的在于避免产生重复数据或者说利用数据存储中间件的事务特性确保数据的精准性,比如大家熟悉的mysql,我们在程序开始时,只需...
    99+
    2024-04-02
  • 前端与RabbitMQ实时消息推送未读消息小红点实现示例
    目录引言RabbitMQ 搭建1、开启 mqtt 协议服务端消息发送1、mqtt 客户端依赖包2、消息发送者前端消息订阅测试总结 引言 前几天粉丝群里有个小伙伴问过:web ...
    99+
    2024-04-02
  • MFC模拟实现自定义消息发送
    目录自定义消息第一步:定义自定义消息名称以及ID第二步:发送自定义消息第三步:自定义消息映射第四步:自定义消息实现模拟系统消息wParam参数LPARAM参数在MFC框架下,有很多系...
    99+
    2024-04-02
  • SpringBoot实现MQTT消息发送和接收方式
    目录Spring integration交互逻辑1、maven依赖2、yaml配置文件3、mqtt生产者消费者配置类4、消息处理类 5、mqtt发送接口 6、mq...
    99+
    2023-03-11
    SpringBoot MQTT消息 MQTT消息发送 MQTT消息接收
  • SpringBoot如何实现MQTT消息发送和接收
    今天小编给大家分享一下SpringBoot如何实现MQTT消息发送和接收的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。Spr...
    99+
    2023-07-05
  • fiv.js实现flv文件blob流实时播放的项目实践
    目录一、前言二、 过程1、开端2、出师不利3、峰回路转--参考旧项目4、flv.js5、hls.js6、rtmp流最后一、前言 最近遇到个需求,有个监控视频需要在网页实时播放,后台提...
    99+
    2023-05-16
    flv文件blob流实时播放 flv文件实时播放
  • PHP实现在线即时通讯系统消息的发送和接收
    随着人们生活方式的改变和网络技术的不断发展,即时通讯已经成为现代人必不可少的沟通方式之一。在这种趋势下,各种在线即时通讯系统应运而生。既然在不同地方的人可以在同一时间内交换消息,那么在线即时通讯系统是如何实现消息的传递的呢?本文将介绍通过 ...
    99+
    2023-05-24
    PHP 消息发送 在线通讯
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作