客户端分组的实现

除了 12.2 节中所讲的 3 种常规通信类型外,在服务器端向客户端发送消息时,还可以对要接收消息的客户端进行分组,下面进行讲解。

创建分组

使用 socket.io 模块实现客户端分组功能时可以通过 socket.join() 方法进行分组,其语法格式如下:

socket.join(room)

参数 room 表示分组的组名。

例如,下面代码创建了两个分组:group1group2

socket.on('group1', function (data) {
     socket.join('group1');
});
socket.on('group2',function(data){
     socket.join('group2');
});

一个客户端可以进入多个分组。

退出分组

客户端能够进入分组,同样也可以退出分组,退出分组使用 socket.leave() 方法实现,其语法格式如下:

socket.leave(data.room);

其中,data 为要退出分组的客户端;room 为要退出的分组的组名。

例如,下面代码使指定用户(由客户端传递的数据 data 提供)退出 group2 分组:

socket.on('leavegroup2', function (data) {
     var room="group2"
     socket.leave(data.room);
     io.sockets.in('group2').emit('leave2', data);
});

向分组中的用户发送消息

向分组中的用户发送消息时,可以分为两种情况。第一种情况是,分组中的所有人(包括自己)都可以接收到消息,这时可以使用 io.sockets.in().emit() 方法,其语法格式如下:

io.sockets.in(room).emit(event,data)

第二种情况是,分组中除自己以外的所有人都可以接收该消息,这时可以使用 io.sockets.broadcast.to().emit() 方法,其语法格式如下:

io.sockets.broadcast.to(room).emit(event,data)

参数 room 表示接收该消息的分组的组名,参数 event 表示要发送的事件,参数 data 表示要发送的数据。

【例12.5】实现进群通知和退群通知。(实例位置:资源包\源码\12\05)

大家知道无论 QQ 群还是微信群,当有新用户进群时,所有群成员都能接收到进群通知,而在退群时,群内的管理员可以收到退群通知。本实例将模拟并升级该功能,实现用户进群或者退群时所有群成员都可以收到通知的功能。步骤如下。

(1) 创建 socket 服务器端 js.js 文件,在服务器端监听的事件有 group1group2leavegroup1leavegroup2,分别表示客户端进入 group1 分组、客户端进入 group2 分组、客户端离开 group1 分组和客户端离开 group2 分组,在监听到相应的事件发生时,分别向相应的分组内发送进入和离开的通知消息。代码如下:

//引入模块
var fs = require('fs');
//创建服务器
var server = require('http').createServer();
var io = require('socket.io')(server);
server.on('request', function (request, response) {
     //读取客户端文件
     fs.readFile('index.html', function (error, data) {
          response.writeHead(200, {'Content-Type': 'text/html'});
          response.end(data);
     });
}).listen(52273, function () {
     console.log('服务器监听地址是 http://127.0.0.1:52273');
});
//监听connection事件
io.sockets.on('connection', function (socket) {
     //创建分组名称
     var roomName = null;
     //监听客户端进入group1分组
     socket.on('group1', function (data) {
          socket.join('group1');
          io.sockets.in('group1').emit('welcome1', data);
     });
     //监听客户端进入group2分组
     socket.on('group2', function (data) {
          socket.join('group2');
          io.sockets.in('group2').emit('welcome2', data);
     });
     //监听客户端离开group1分组
     socket.on('leavegroup1', function (data) {
          var roomName="group1"
          socket.leave(data.room);
          io.sockets.in('group1').emit('leave1', data);
     });
     //监听客户端离开group2分组
     socket.on('leavegroup2', function (data) {
          var roomName="group2"
          socket.leave(data.room);
          io.sockets.in('group2').emit('leave2', data);
     });
});

(2) 新建客户端页面 index.html,在该页面中定义一个 show() 函数,用来以指定的格式显示进群和退群通知;然后分别监听服务器端发送的进入和离开事件,并调用 show() 函数显示相应的信息;另外,在客户端页面中,需要使用 socket.emit() 方法向服务器端发送 group1group2leavegroup1leavegroup2 这 4 个事件,以便让服务器端进行监听。index.html 页面的关键代码如下:

    <script src="/socket.io/socket.io.js"></script>
    <script>
        window.onload = function () {
            // 声明变量.
            var nickname = ""
            var socket = io.connect();
//            监听事件
            socket.on("welcome2", function (data) {
                show(2, "进入", data)   //客户进入2群
            })
            socket.on("welcome1", function (data) {
                show(1, "进入", data)//客户进入1群
            })
            socket.on("leave1", function (data) {
                show(1, "退出", data)  //客户离开1群
            })
            socket.on("leave2", function (data) {
                show(2, "退出", data)//客户离开2群
            })
            document.getElementById("group1").onclick = function () {
                if (nickname == "") {
                    setName()
                }
                socket.emit("group1", nickname)  //发送进入1群事件
            }
            document.getElementById("group2").onclick = function () {
                if (nickname == "") {
                    setName()
                }
                socket.emit("group2", nickname)  //发送进入2群事件
            }
            document.getElementById("leavegroup1").onclick = function () {
                socket.emit("leavegroup1", nickname)//发送离开1群事件
            }
            document.getElementById("leavegroup2").onclick = function () {
                socket.emit("leavegroup2", nickname)  //发送离开2群事件
            }
            document.getElementById("setName").onclick = function () {
                setName()
            }

            function setName() {
                var name = document.getElementById("name")
                if (name.value == "") {
                    alert("请设置昵称")
                }
                else {
                    nickname = name.value
                    document.getElementById("none").style.display = "none"
                }
            }

            function show(room, out, data) {
                var box = document.getElementById("box" + room)
                box.innerHTML += "<li><span class='red'>" + data + "</span><span>" + out + "</span><span>本群</span></li>"
            }
        };
    </script>
</head>
<body>
<fieldset>
    <legend>进群</legend>
    <label id="none"><span>设置昵称:</span><input type="text" id="name" style="">
        <button type="button" id="setName">设置名称</button>
    </label>
    <div class="btnbox">
        <button type="button" id="group1">进入1群</button>
        <button type="button" id="group2">进入2群</button>
        <button type="button" id="leavegroup1">退出1群</button>
        <button type="button" id="leavegroup2">退出2群</button>
    </div>
    <div>
        <ul id="box1">
            <p>客户1群</p>
        </ul>
        <ul id="box2">
            <p>客户2群</p>
        </ul>
    </div>
</fieldset>

运行 js.js 文件,然后分别打开 3 次 http://127.0.0.1:52273 网页地址,其初始效果如图 12.20 所示,依次在浏览器中设置昵称,设置昵称后的效果如图 12.21 所示。

image 2024 04 17 11 49 36 253
Figure 1. 图12.20 浏览器初始运行效果
image 2024 04 17 11 49 56 608
Figure 2. 图12.21 设置昵称后的效果

在 3 个打开的页面中分别单击进群和退群的按钮,相应群中的客户端即可显示进群或者退群的消息,效果如图 12.22 所示。

image 2024 04 17 11 50 33 839
Figure 3. 图12.22 显示进群或退群消息