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

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

Node聊天程序实例02:chat_server.js的更多相关文章

  1. Node聊天程序实例01

    作者:vousiu 出处:http://www.cnblogs.com/vousiu 本实例参考自Mike Cantelon等人的<Node.js in Action>一书. 本实例要实现 ...

  2. Node聊天程序实例04:chat_ui.js

    作者:vousiu 出处:http://www.cnblogs.com/vousiu 本实例参考自Mike Cantelon等人的<Node.js in Action>一书. 这个程序在客 ...

  3. Node聊天程序实例03:chat.js

    作者:vousiu 出处:http://www.cnblogs.com/vousiu 本实例参考自Mike Cantelon等人的<Node.js in Action>一书. chat.j ...

  4. Node聊天程序实例06:server.js

    作者:vousiu 出处:http://www.cnblogs.com/vousiu 本实例参考自Mike Cantelon等人的<Node.js in Action>一书. server ...

  5. Node聊天程序实例05:index.html和style.css

    作者:vousiu 出处:http://www.cnblogs.com/vousiu 本实例参考自Mike Cantelon等人的<Node.js in Action>一书. index. ...

  6. 小程序实例:用js方法splict()、indexOf()、push()、replace()等操作数组Array的增删改查

    一.增加数组子级 1.Array.push() 定义和用法 向数组的末尾处添加一个或多个子集,并返回新数组的长度 语法 var array=["好","扎在那个" ...

  7. WinSocket聊天程序实例(多线程)

    #pragma comment(lib,"Ws2_32.lib") #include <stdio.h> #include <Winsock2.h> SOC ...

  8. boost asio异步读写网络聊天程序client 实例具体解释

    boost官方文档中聊天程序实例解说 数据包格式chat_message.hpp <pre name="code" class="cpp">< ...

  9. boost asio异步读写网络聊天程序客户端 实例详解

    boost官方文档中聊天程序实例讲解 数据包格式chat_message.hpp <pre name="code" class="cpp">< ...

随机推荐

  1. kali 更改root密码

    sudo root passwd root 然后输入两次密码即可

  2. XPath、XQuery 以及 XSLT 函数

    存取函数 名称 说明 fn:node-name(node) 返回参数节点的节点名称. fn:nilled(node) 返回是否拒绝参数节点的布尔值. fn:data(item.item,...) 接受 ...

  3. Spring jar下载地址:

    https://repo.spring.io/release/org/springframework/spring/

  4. 多线程java的concurrent用法详解(转载)

    我们都知道,在JDK1.5之前,Java中要进行业务并发时,通常需要有程序员独立完成代码实现,当然也有一些开源的框架提供了这些功能,但是这些依然没有JDK自带的功能使用起来方便.而当针对高质量Java ...

  5. oracle学习笔记

    --Oracle查询当前版本select * from v$version;----------Oracle 查询服务器端编码----------select * from v$nls_paramet ...

  6. visual studio 两个以上sln 引用同一个project ,生成时会改变projectguid问题

    当两个以上解决方案添加现有项,选择了同一个项目,那么在 sln 文件中,会自己带一个guid. 当打开两个解决方案,一个生成时,会影响另一个的project值,导致每次都看到了签出. 解决办法,打开共 ...

  7. css深入理解z-index

    z-index取值 z-index:auto;z-index:<integer>;z-index:inherit;继承 特性: 1.支持负值2.支持css3 animation动画;3.在 ...

  8. nginx跨域配置

    假设前端页面的地址为: 192.168.1.1/arcgis40/index.html 页面物理路径为: X:\nginx-1.9.15\html\arcgis40 那么请求服务时,当ajax代码如下 ...

  9. Oracle基本sql操作

    1.查询用户下的所有表 查询用户下的所有表 select distinct table_name from user_tab_columns; 2.搜索出前N条记录 Select a.*,rownum ...

  10. Ansible 学习笔记

    最近因为需要管理很多台机器,而这些机器又需要频繁重新安装,实在受不了Puppet需要在每个客户机上都安装一遍,于是转头开始学些Ansible.根据这段时间的使用,这个确实是神器,唯一的感觉就是相见恨晚 ...