Node.js基于Socket.io实现私聊与公聊聊天室开发详解

作者:接口漫谈时间:2026-10-29 17:23:18浏览:151

本文详细讲解如何在Node.js环境中利用Socket.io搭建具备私聊和公聊功能的聊天室。文章从Socket服务监听配置入手,解析连接事件处理,重点阐述通过全局对象映射Socket实例以实现服务器中转的私聊逻辑,并包含用户加入、消息发送及断开连接时的状态维护代码示例。

Node.js Socket.io聊天室实现概述

首先展示最终实现的界面效果。

Node.js Socket.io聊天室实现概述

在前文介绍使用Angular与Node.js结合socket.io构建基础聊天室及多人聊天功能的基础上,本文将继续深入探讨如何在Node.js中利用socket实现具体的私聊与公聊聊天室功能,详细内容如下。

在Node.js应用生态中,socket相关技术表现尤为突出。socket.io在GitHub上获得了数万星的关注,其流行程度不亚于Express框架。为了帮助开发者更好地理解socket.io的实际应用,下面进行具体说明。

示例项目的访问地址为http://chat.lovewebgames.com/。

完整源代码可下载至https://github.com/tianxiangbing/chat。

由于服务器和数据库均采用了国外免费资源,访问速度可能会受到一定影响。

Socket服务端口配置

首先阐述对socket.io的理解:WebSocket机制类似于开启一个端口服务来监控通信流量。因此,我们可以依赖当前站点的80端口启动socket服务,也可以将其部署在其他端口上,例如:

具体实现代码如下:

require('socket.io').listen(3000);

上述代码表示监听3000端口。由于使用的免费服务器没有权限开启其他端口,因此仍使用80端口。鉴于80端口已被Express占用,所以在启动Express服务时传入了服务器实例。

相关代码如下:

var server = http.createServer(app);
var socket = require(‘./socket/msg')(server);

随后,在msg.js文件中的实现方式如下:

代码片段如下:

var db = require('../db/mysql');
var sio = require('socket.io');
var IO = function(server) {
var io = sio.listen(server)

至此配置完成。其中db用于创建MySQL连接,不属于本节讨论范围,故省略。

连接事件与消息处理机制

在socket.io中,首先需要创建io通道的连接,然后监视其中的socket事件,因为Node.js是事件驱动模型。具体代码如下:

代码如下:

io.on('connection', function(socket) {
console.log('a user connected.');
socket.on('disconnect', function() {
console.log('user disconnected.');
        });
})

当有用户连接时,代码进入connection回调。如果是公聊,可以直接使用以下方式进行广播:

代码如下:

io.emit('chat message', {});

私聊功能的Socket映射与中转逻辑

但本例涉及私聊,因此需要将socket对象临时保存在全局变量中,以便私聊对象能通过服务器找到目标用户的socket。这并非完全的点对点通信,而是经过服务器中转:消息先传给服务器,服务器再查找目标用户的socket对象并发出。整个流程如下,这里使用类数组对象进行存储。

代码示例如下:

var users = {},
usocket = {};
socket.on('user join', function(data) {
users[username] = username;
usocket[username] = socket;
})

由于需要用户名登录,这里将用户名作为唯一标识(此为示例,未处理用户名重复情况)。使用类数组形式的优势在于无需循环即可快速查找。当向用户A发送私聊时,先在usocket中查找其socket,然后调用其emit方法。


function sendUserMsg(data) {
 if (data.to in usocket) {
 console.log('================')
 console.log('to' + data.to, data);
 usocket[data.to].emit('to' + data.to, data);
 usocket[data.user].emit('to' + data.user, data);
 console.log('================')
 }
}

这里emit调用两次的原因是:在向对方发送消息的同时,自己也需接收该消息以显示在界面上。这样做有两个好处:一是接口统一,聊天内容均由服务器下发;二是确认发送成功。

在客户端监听时,使用“to+用户名”的事件名进行监听。


socket.on('to' + user, function(data) {
 //console.log(data);
 formatMsg(data);
})

这样,无论是发送还是接收的消息,都会进入该事件监听器。最后,在用户断开连接时,务必删除对应的对象。


socket.on('disconnect', function() {
 console.log('disconnect')
 if (username) {
 counter--;
 delete users[username];
 delete usocket[username];
 if (home.name == username) {
  homeLeave(username);
 }
 sendmsg({
  type: 0,
  msg: "用户<b>" + username + "</b>离开聊天室",
  counter: counter,
  users: users
 })
 }
});

至此,功能实现完毕。

作者最新文章