你的位置:首页 > Java教程

[Java教程]Node聊天程序实例02:chat_server.js


作者: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 --------

清理与这个用户相关的变量。