最近这两天在看node.js,看大家好多人都拿聊天室这个项目来练习node,我也来凑个热闹。
整个项目是基于node.js ,webSocket的实现实时通信,管理多个房间,统计房间内用户,切换不同房间等功能。
看着nodejs实战这本书,但书中代码老旧,读懂书中代码后,去官网查最新文档,对比着修改代码,最后将功能重新实现。既屡了逻辑,也了解了最新文档,收获蛮多的。
目录结构
代码:
server.js:
let http = require('http'); //内置的http模块提供了HTTP服务器和客户端功能
let fs = require('fs'); //内置的fs模块提供了与文件系统相关的功能
let path = require('path'); //内置的path模块提供了与文件系统路径相关的功能
let mime = require('mime'); //附加的mime模块有根据文件扩展名得出MIME类型的能力
let cache = {}; //cache是用来缓存文件内容的对象
let chatServer = require('./lib/chat_server');
function send404(response) {
response.writeHead(404, {
'Content-Type': 'text/plain'});
response.write('Error 404: resource not found.');
response.end();
}
function sendFile(response, filePath, fileContents) {
response.writeHead(
200,
{
"content-type": mime.getType(path.basename(filePath))} );
response.end(fileContents);
}
function serveStatic(response, cache, absPath) {
if (cache[absPath]) { //检查文件是否缓存在内存中
sendFile(response, absPath, cache[absPath]); //从内存中返回文件
} else {
fs.access(absPath, (err) => { //检查文件是否存在
if (err) {
send404(response);
} else {
fs.readFile(absPath, function(err, data) {
//从硬盘中读取文件
if (err) {
send404(response);
} else {
cache[absPath] = data;
sendFile(response, absPath, data); //从硬盘中读取文件并返回
}
});
}
});
}
}
let server = http.createServer(function(request, response) {
//创建HTTP服务器,用匿名函数定义对每个请求的处理行为
let filePath = false;
if (request.url === '/') {
filePath = 'public/index.html';
} else {
filePath = 'public' + request.url; //将URL路径转为文件的相对路径
}
let absPath = './' + filePath;
serveStatic(response, cache, absPath); //返回静态文件
});
server.listen(3000, function() {
console.log("Server listening on port 3000.");
});
chatServer.listen(server);
chat-server.js:
let socketio = require('socket.io');
let io;
let guestNumber = 1;
let nickNames = {};
let namesUsed = [];
let currentRoom = {};
exports.listen = function(server) {
io = socketio.listen(server); //启动Socket.IO服务器,允许它搭载在已有的HTTP服务器上
// io.set('log level', 1);
io.sockets.on('connection', function (socket) {
//定义每个用户连接的处理逻辑
guestNumber = assignGuestName(socket, guestNumber,nickNames, namesUsed); //在用户连接上来时赋予其一个访客名
joinRoom(socket, 'Lobby'); //在用户连接上来时把他放入聊天室Lobby里
handleMessageBroadcasting(socket, nickNames); //处理用户的消息,更名,以及聊天室的创建和变更
handleNameChangeAttempts(socket, nickNames, namesUsed);
handleRoomJoining(socket);
socket.on('rooms', function() {
//当用户发出请求时,向其提供已经被占用的聊天室的列表
socket.emit('rooms', io.sockets.adapter.rooms);
});
handleClientDisconnection(socket, nickNames,