作者:vousiu
出处:http://www.cnblogs.com/vousiu
本实例参考自Mike Cantelon等人的《Node.js in Action》一书。
chat_server.js:
客户端和服务端就是不断通过socket.io事件来通信:
chat_server ---------------> chat_ui
chat_server <--------------- chat_ui
其中的这一段:
socket.on('rooms', function() { socket.emit('rooms', io.sockets.manager.rooms); });
注册异步回调函数:
<--------------- 'rooms' ------------------
|
`------------- 'rooms' ---------------> 全部房间。
这段代码与客户端定时请求所有房间号相配合,不断刷新可用房间列表。其实也可以在用户开新房间时再对所有用户广播,那样就不用定期刷新了。但是那样的话当最后一个用户离开原房间时,那个房间不会消失。
function assignGuestName(socket, guestNumber, nickNames, nameUsed) { var name = 'Guest' + guestNumber; nickNames[socket.id] = name; socket.emit('nameResult', { success: true, name: name }); nameUsed.push(name); return guestNumber + 1; }
chat_server ----------- 'nameResult' ------------> {success: true, name:'Guestxxx'}
更新服务器里与name有关的变量。
(用户还没收到该事件消息,服务器就继续执行后面的代码操作也没事,因为服务器这里的已经存储了每个用户的名称状态,它是一致的。)
我觉得这里后三个参数不需要传,因为它们本来就是服务器本地数据,传和不传都是一样的,而且这个函数不是异步函数,是立即执行的。如果是异步函数,反倒会造成不一致的情况。
function joinRoom(socket, room) { socket.join(room); currentRoom[socket.id] = room; socket.emit('joinResult', {room: room}); socket.broadcast.to(room).emit('message', { text: nickNames[socket.id] + ' has joined ' + room + '.' }); var usersInRoom = io.sockets.clients(room); if (usersInRoom.length > 1) { var usersInRoomSummary = 'Users currently in ' + room + ': '; for (var index in usersInRoom) { var userSocketId = usersInRoom[index].id; usersInRoomSummary + nickNames[userSocketId] + ' '; } } socket.emit('message', {text: usersInRoomSummary}); }
更新与room相关的本地变量。
把当前socket的用户加入socket的'roomName'分组。
chat_server ----------- 'joinResult' ------------> {room: 'roomName'}
chat_server --------- (broadcast) 'message' ----------> {text: '当前用户名 has joined roomName.'}
(这句待议,为什么是由socket来broadcast而不是io?)
同步获取房间里所有的人名。
chat_server ----------- 'message' ------------> {text: '房间内所有人名'}
function handleMessageBroadcasting(socket) { socket.on('message', function(message) { socket.broadcast.to(message.room).emit('message', { text: nickNames[socket.id] + ': ' + message.text }); }); }
注册异步回调函数。
<--------------- 'message' ------------------ message
|
`------------- (broadcast:message.room) 'message' ---------------> {text: 'nickName: message'}
function handleNameChangeAttempts(socket, nickNames, nameUsed) { socket.on('nameAttempt', function(name) { if (name.indexOf('Guest') == 0) { socket.emit('nameResult', { success: false, message: 'Name cant begin with Guest' }); } else { if (nameUsed.indexOf(name) == -1) { var previousName = nickNames[socket.id]; var previousNameIndex = nameUsed.indexOf(previousName); nameUsed.push(name); nickNames[socket.id] = name; delete nameUsed[previousNameIndex]; socket.emit('nameResult', { success: true, name: name }); } else { socket.emit('nameResult', { success: false, message: 'Name already used.' }); } } }); }
注册异步回调函数。
<--------------- 'nameAttempt' ------------------ name
|
`------------- 'nameResult' ---------------> {success: true||false, message: 'name'||'why fail'}
跟前面那个回调函数不一样,这个回调函数需要服务器全局变量和对其进行修改。
同理,这里后两个参数传的是引用,传跟不传也没什么不同。(是不传就无法访问吗?)
function handleRoomJoining(socket) { socket.on('join', function(room) { socket.leave(currentRoom[socket.id]); joinRoom(socket, room.newRoom); }); }
注册异步回调函数。
<--------------- 'join' ------------------ room
|
socket离开原来的分组
|
joinRoom(socket, room.newRoom)
这个也需要服务器全局变量,它就没有传参。
function handleClientDisconnection(socket) { socket.on('disconnect', function() { var nameIndex = nameUsed.indexOf(nickNames[socket.id]); delete nameUsed[nameIndex]; delete nickNames[socket.id]; }) }
注册异步回调函数。
<------ x ------- 'disconnect' ------- x --------
清理与这个用户相关的变量。