Nodejs 新手关于使用 socket.io 建立一个简单聊天室的问题
Nodejs 新手关于使用 socket.io 建立一个简单聊天室的问题
各位大神,我是一个node.js新手,最近在学习《《Node.js实战》》这本书进行学习,书上有一个简单聊天室的例子,主要用socket.io
来实现。下面是我的仓库,我写了一半的项目名字是:node_chat,代码不多,都在里边,
我的仓库
下图为服务器文件的一段代码
有用户链接上来后,执行guestNumber,joinRoom,handleNameChangeAttempts等方法。
以上图assignGuestName为例子,执行完毕后用
socket.emit(‘nameResult’,{
success:true,
name:name
});
给客户端返回,客户端成功用socket.on()接收。
同样,
JoinRoom函数调用后客户段也成功接收,下面上一些客户端的代码
但是handleNameChangeAttempts却出问题了,下面上其代码
本人调试可知已经执行到了
socket.emit(‘nameResult’,{
success:true,
name:name
});
socket.broadcast.to(currentRoom[socket.id]).emit(‘message’,{
text:previousName + 'is now known as ’ + name + ‘.’
});
可是执行完之后就返回了404,跳不到客户端的index.html了,奇怪为什么都执行到socket.emit了,前两个方法可以,后两个方法就错了,调试了挺久找不到问题,求助各位大神
当然,我可以帮助你解决这个问题。根据你的描述,handleNameChangeAttempts
方法出现问题,导致无法正确发送消息到客户端。让我们一起检查并修正这个问题。
服务器端代码
首先,我们来看一下 handleNameChangeAttempts
方法。假设你的代码类似于以下结构:
function handleNameChangeAttempts(socket) {
socket.on('attemptNameChange', function(name) {
var currentName = getName(socket);
if (name !== currentName) {
if (nameExists(name)) {
socket.emit('nameResult', {
success: false,
message: 'That name is already taken.'
});
} else {
socket.emit('nameResult', {
success: true,
name: name
});
// 广播名字变更信息
socket.broadcast.to(currentRoom[socket.id]).emit('message', {
text: currentName + ' is now known as ' + name + '.'
});
// 更新用户名
changeUserName(socket, name);
}
}
});
}
客户端代码
确保客户端代码正确处理这些事件。例如:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect();
// 处理名字变更结果
socket.on('nameResult', function(result) {
if (result.success) {
console.log('You are now known as ' + result.name + '.');
} else {
console.log(result.message);
}
});
// 处理消息广播
socket.on('message', function(message) {
console.log(message.text);
});
</script>
可能的问题及解决方案
-
检查房间分配:确保
currentRoom
对象中包含正确的房间信息。你可以打印currentRoom
来检查是否有错误。console.log(currentRoom);
-
检查 socket.id:确保
socket.id
正确地映射到房间。你可以手动检查或调试。 -
确保正确的事件监听器:确保客户端正确地监听了
nameResult
和message
事件。 -
检查网络请求:如果客户端返回404错误,可能是某些静态资源(如HTML文件)没有正确加载。确保你的服务器正确地提供了这些资源。
示例代码
以下是完整的服务器端代码示例:
const io = require('socket.io')(server);
let currentRoom = {};
let usernames = {};
io.on('connection', function(socket) {
socket.on('addUser', function(username) {
// 添加用户名到全局变量
usernames[username] = username;
socket.username = username;
socket.room = 'default';
socket.join('default');
currentRoom[socket.id] = 'default';
// 发送欢迎消息
socket.emit('updatechat', 'SERVER', 'you have connected to default');
socket.broadcast.to('default').emit('updatechat', 'SERVER', username + ' has connected');
});
socket.on('switchRoom', function(newRoom) {
socket.leave(socket.room);
socket.join(newRoom);
socket.room = newRoom;
currentRoom[socket.id] = newRoom;
socket.emit('updatechat', 'SERVER', 'you have connected to ' + newRoom);
socket.broadcast.to(socket.room).emit('updatechat', 'SERVER', socket.username + ' has connected to ' + newRoom);
});
socket.on('sendMessage', function(msg) {
socket.broadcast.to(socket.room).emit('updatechat', socket.username, msg);
});
handleNameChangeAttempts(socket);
});
function handleNameChangeAttempts(socket) {
socket.on('attemptNameChange', function(name) {
var currentName = socket.username;
if (name !== currentName) {
if (usernames[name]) {
socket.emit('nameResult', {
success: false,
message: 'That name is already taken.'
});
} else {
socket.emit('nameResult', {
success: true,
name: name
});
socket.broadcast.to(currentRoom[socket.id]).emit('message', {
text: currentName + ' is now known as ' + name + '.'
});
socket.username = name;
usernames[name] = name;
}
}
});
}
希望这些建议能帮助你解决问题!
看了看你的代码,我觉得你这里出现的问题应该是没有理解 nodejs 的异步到底是怎么回事。
我看代码中有不少 emit 和 broadcast 的操作都没有接收回调函数,你是按同步代码的写法在写 nodejs 的异步代码,这样是很容易出错的。
你调调看是不是这方面的原因
呃,有一处 $(’$send-message’) 应该是 $(’#send-message’)。 哎,用node-monkey也很难调试找到这种bug啊。
根据你的描述,handleNameChangeAttempts
方法在执行 socket.emit
和 socket.broadcast.to
时遇到了问题,导致客户端返回 404 错误。这可能是由于以下几个原因:
- 房间 ID 或 Socket ID 错误:确保你在
socket.broadcast.to(currentRoom[socket.id])
中使用的房间 ID 是正确的。 - Socket.io 版本问题:不同版本的 Socket.io API 可能有所不同,确保你使用的 API 与 Socket.io 版本匹配。
- 事件名称或参数错误:确保你在客户端监听的事件名称和参数与服务端发送的完全一致。
以下是一个简单的示例,展示如何正确处理用户名更改:
服务器端代码示例
const io = require('socket.io')(server);
io.on('connection', (socket) => {
let currentRoom;
const assignGuestName = (socket, name, rooms) => {
// 赋予一个默认用户名并加入房间
socket.emit('nameResult', {
success: true,
name: name
});
};
const joinRoom = (socket, room) => {
socket.join(room);
currentRoom = room;
socket.emit('roomJoined', { room: room });
socket.broadcast.to(room).emit('message', { text: `${socket.client.id} has joined ${room}.` });
};
const handleNameChangeAttempts = (socket, name, previousName, rooms) => {
const isTaken = rooms.some(room => room.name === name);
if (isTaken) {
socket.emit('nameResult', {
success: false,
message: 'The desired name is already taken.'
});
} else {
socket.emit('nameResult', {
success: true,
name: name
});
socket.broadcast.to(currentRoom).emit('message', {
text: `${previousName} is now known as ${name}.`
});
}
};
socket.on('createRoom', (room) => {
joinRoom(socket, room);
});
socket.on('setName', (data) => {
handleNameChangeAttempts(socket, data.name, data.previousName, []);
});
});
客户端代码示例
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();
function createRoom(room) {
socket.emit('createRoom', room);
}
function setName(name) {
socket.emit('setName', { name: name, previousName: document.getElementById('currentName').innerText });
}
socket.on('nameResult', (result) => {
if (result.success) {
document.getElementById('currentName').innerText = result.name;
} else {
alert(result.message);
}
});
socket.on('message', (msg) => {
console.log(msg.text);
});
</script>
关键点解释
- assignGuestName: 发送用户名结果给客户端。
- joinRoom: 加入房间,并广播消息给其他用户。
- handleNameChangeAttempts: 检查用户名是否已存在,如果不存在则更新用户名,并广播给其他用户。
请确保你的代码结构和逻辑与上述示例一致,并检查网络请求以确保没有 404 错误。