在这个学期的计算机网络原理的实验任务二中,要求学生可以选做基于Socket编程的聊天程序。考虑到之前学习过Node.js,结合去年暑假开发跨端APP的经验,决定边学边做,实现一个简单的实时聊天程序。大概用时两天。当然,整体时间还是很紧张的。
使用前后端分离的方式进行开发。
前端使用uni-app跨端框架。后端使用Express框架。
1. 录屏展示
2. 前端
- Vue.js + uni-app + weapp.socket.io
- scss实现样式
3. 后端
- Express(Node.js Web应用程序框架) + Socket.IO
- 建立一个专门用来即时通讯的端口8081
4. 流程图
- 客户端-服务端-多个客户端
- 客户端、服务端:都是接收和发送两个处理
- 服务端:广播
5. 实际效果
(1)启动后端
(2)启动前端
可以在HBuilderX里,选择直接运行到浏览器。当然,同样支持真机调试和模拟器调试。
(3)功能演示
- 默认页
- 支持选择头像
- 输入用户名后点击”加入“。
- 我们可以以不同的身份加入。每个用户加入群聊后都会显示欢迎语。同样地,可以在群里中发送消息。
- 分别以李四和王五的身份加入聊天室。加入后三人的界面如下。
- 在三人都加入群聊后,李四发布一条消息。
- 此时张三和王五也都可以在各自的界面里收到李四的消息。
- 如果关闭页面,或者返回上一级页面,即认为该用户退出。如果刷新页面,认为该用户是退出后重新进入聊天室。如图,我们关闭王五的界面。刷新重进李四的界面。
- 刷新重进后不保存之前的聊天记录。因为考虑到时间有限,没有设计数据库。
- 下面演示私聊功能。
- 在学生发送消息后,老师的界面上该学生的头像上会显示红点。打开消息后红点消失。
- 如图,接收消息是成功的。同样的,回复消息也是成功的。学生和老师都可以在各自的界面看到这几条消息。对方发过来的消息显示在左侧,自己发出去的消息显示在右侧。支持查看发送消息的具体时间。
- 其他细节:
- 在群聊时,对于自己发送的消息,只显示消息发送时间。对于接受到的对方发送的消息,显示对方用户名和消息发送时间。
- 头部导航栏不显示自己的头像,只显示其他可私聊群成员的头像。
6. 相关代码和说明
- 注意使用合适的依赖版本
"dependencies": {
"express": "^4.17.1",
"socket.io": "^2.3.0"
}
- 大概的流程:
- 客户端使用this.socket.emit(‘msg’,data);发送信息
- 服务端使用socket.on接收消息
- 服务端使用socket.broadcast.emit广播消息
- 客户端接收广播后的消息并渲染
- 具体细节还需要看Socket.IO官方文档 https://socket.io
- 客户端需要用到简单的JavaScript数组方法插入数据。
- 服务端需要建立Socket.IO对象。
7. 小结
- 前端(客户端)代码量相对最大,很多是样式方面的代码。此外,函数方面举例:
- 获取当前日期
- 发送消息
- 加入群聊
- 欢迎消息
- 获取个人信息
- 退出群消息提醒
- 获取即时信息渲染
- 获取私聊信息
- 进入私聊
- 私聊界面动画
- 退出
- 后端(服务端)代码其实非常简洁。也要感谢网上的相关参考教程。
const express = require('express')
const app = express()
const port = 3000
let server = app.listen(8081)
let io = require('socket.io').listen(server);
//引入socket.js
require('./model/socket.js')(io);
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(port, () => console.log(`项目已经在端口${port}启动!`))
module.exports = function(io){
let socketList = {};
let users = [];
io.sockets.on('connection',function(socket){
console.log('连接到http://10.4.9.73:8081成功!');
socket.on('join',(name,img) => {
socket.name = name;
socketList[name] = socket.id;
let user = {name:name,img:img,id:socket.id,tip:false};
users.push(user);
socket.broadcast.emit('welcome',name,users);
socket.emit('myself',name,users,socket.id);
});
// 接收信息
socket.on('message',data => {
// 广播
socket.broadcast.emit('sendMsg',data);
})
// 私聊信息
socket.on('msg',data => {
//console.log(data.tid);
// 广播
socket.to(data.tid).emit('sMsg',data);
})
// 用户离开
socket.on('disconnecting',function(){
if(socketList.hasOwnProperty(socket.name)){
// 删除
delete socketList[socket.name];
for(let i=0;i<users.length;i++){
if(users[i].name == socket.name){
users.splice(i,1);
}
}
// 广播用户退出
socket.broadcast.emit('quit',socket.name,users);
}
})
})
}