socket数据通信类型

使用 socket.io 模块进行 socket 数据通信,主要有 3 种类型,如表 12.3 所示。

image 2024 04 16 23 50 05 747
Figure 1. 表12.3 socket通信类型

本节将分别介绍 socket 的 3 种数据通信类型。

public通信类型

public 通信类型的示意图如图 12.11 所示。客户 A 向 WebSocket 服务器发送一个事件,WebSocket 所有的客户端(客户A、客户B和客户C)都会接收到这个事件。

image 2024 04 16 23 51 13 871
Figure 2. 图12.11 public通信类型示意图

实现 public 通信的方法非常简单,直接使用 io.sockets.emit() 方法即可,其语法格式如下:

io.sockets.emit(event, data)

参数 event 表示要发送的事件,参数 data 表示要发送的数据。

【例12.2】使用 socket 发布一则通知。(实例位置:资源包\源码\12\02)

本实例实现在网页上发布一则通知,发布后,自己和其他客户端都能收到该通知。步骤如下。

(1) 新建一个 js.js 文件,该文件中通过在 WebSocket 服务器端使用 io.sockets.emit() 方法向客户端发送一则通知,主要代码如下:

//引入模块
var http = require('http');
var fs = require('fs');
var socketio = require('socket.io');
//创建Web服务器
var server = http.createServer(function (request, response) {
     //读取客户端index.html文件
     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');
});
//创建WebSocket服务器
var io = socketio(server);
io.sockets.on('connection', function (socket) {
     //监听客户端的事件receiveData
     socket.on('receiveData', function (data) {
          console.log("客户端的消息:"+data)
          io.sockets.emit('serverData', data);            //发送消息(public通信类型)
     });
});

(2) 新建客户端页面 index.html,在该页面中,通过监听服务器端的 serverData 自定义事件,接收服务器端发送的通知并显示。代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
     <meta charset="UTF-8">
     <title>Title</title>
     <style>
          .bold {
               font-weight: bold;
          }
          ul {
               list-style: none;
          }
     </style>
     <script src="/socket.io/socket.io.js"></script>
</head>
<body>
<form action="">
     <fieldset style="width: 360px;margin: 0 auto">
          <legend>发布公告</legend>
          <textarea id="text" style="width: 320px;height: 90px;margin-left: 10px"></textarea><br>
          <div style="text-align: center"><button id="btn" type="button">发送</button></div>
     </fieldset>
     <ul id="box"></ul>
</form>
<script>
     window.onload = function () {
          var nick = "";
          var box = document.getElementById("box")
          const socket = io.connect()
          socket.on("serverData", function (data) {
               console.log(data)
               var html1 = "<span class='bold'>" + data + "</span>"
               var li = document.createElement("li")
               li.innerHTML += html1
               box.append(li)
          })
          document.getElementById("btn").onclick = function () {
               var text = document.getElementById("text").value
               socket.emit("receiveData", text)
          }
     }
</script>
</body>
</html>

运行 js.js 文件,然后在浏览器中多次打开 http://127.0.0.1:52273 网页地址(这里打开了 3 次),此时打开的页面的初始效果相同,如图12.12所示。

image 2024 04 16 23 54 38 492
Figure 3. 图12.12 客户端的初始运行效果

在任意一个对话框中,输入一则通知后,单击 “发送” 按钮,此时就可以看到浏览器中的 3 个打开页面中都显示该通知,如图 12.13 所示。

image 2024 04 16 23 55 15 551
Figure 4. 图12.13 public 通信的效果

broadcast通信类型

broadcast 通信类型的示意图如图 12.14 所示。客户 A 向 WebSocket 服务器发送一个事件,WebSocket 的客户 A 之外的其他所有客户端都会接收到这个事件。

image 2024 04 17 10 54 26 461
Figure 5. 图12.14 broadcast通信类型示意图

实现 broadcast 通信的方法非常简单,直接使用 socket.broadcast.emit() 方法即可,其语法格式如下:

socket.broadcast.emit(event, data)

参数 event 表示要发送的事件,参数 data 表示要发送的数据。

【例12.3】实现群发消息功能。(实例位置:资源包\源码\12\03)

本实例实现群发一条消息,而发布者本人看不到该消息,步骤如下。

(1) 新建一个 js.js 文件,该文件中通过在 WebSocket 服务器端使用 socket.broadcast.emit() 方法向客户端群发消息,主要代码如下:

//引入模块
var http = require('http');
var fs = require('fs');
var socketio = require('socket.io');
//创建Web服务器
var server = http.createServer(function (request, response) {
     //读取index.html
     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');
});
//创建WebSocket服务器
var io = socketio(server);
io.sockets.on('connection', function (socket) {
     //监听客户端的事件clientData
     socket.on('receiveData', function (data) {
          console.log("客户端的消息:"+data)
          socket.broadcast.emit('serverData', data);  //发送消息(broadcast通信类型)
     });
});

(2) 新建客户端页面 index.html,在客户端页面中,通过监听服务器端的 serverData 自定义事件,接收服务器端发送的消息并显示。代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
     <meta charset="UTF-8">
     <title>Title</title>
     <script src="/socket.io/socket.io.js"></script>
</head>
<body>
<form action="">
     <fieldset style="width: 200px;margin: 0 auto">
          <legend>发布公告</legend>
          <textarea id="text" cols="50" rows="10"></textarea><br>
          <button id="btn">我写好了</button>
     </fieldset>
     <div id="box"></div>
</form>
<script>
     var box=document.getElementById("box")
     const socket = io.connect()
     window.onload=function () {
          socket.on("serverData", function (data) {
               var html=data+"<br>"
               box.innerHTML+=html                             //将获取的信息添加到div中
          })
          document.getElementById("btn").onclick=function () {
               var text = document.getElementById("text").value
               socket.emit("receiveData", text)                //发送消息
          }
     }
</script>
</body>
</html>

运行 js.js 文件,然后在浏览器中多次打开 http://127.0.0.1:52273 网页地址(这里打开了 3 次,并且,为方便描述,笔者按照打开顺序依次将它们称为 1 号客户端、2 号客户端和 3 号客户端),此时打开的页面的初始效果相同,如图12.15所示。

接下来,在 1 号客户端的文本框中输入消息后,单击 “我写好了” 按钮,即可将消息群发出去,这时 2 号客户端和 3 号客户端可以接收到该消息,但是 1 号客户端接收不到该消息,效果如图 12.16 所示。

image 2024 04 17 10 58 20 506
Figure 6. 图12.15 客户端初始效果
image 2024 04 17 10 58 43 658
Figure 7. 图12.16 群发消息

private通信类型

private 通信类型的示意图如图 12.17 所示。客户 A 向 WebSocket 服务器发送一个事件,WebSocket 会向指定的客户端(如客户 C)发送这个事件。

image 2024 04 17 10 59 51 844
Figure 8. 图12.17 private通信类型示意图

实现 private 通信的方法非常简单,直接使用 io.to(id).emit() 方法即可,其语法格式如下:

io.to(id).emit(event, data)

参数 id 表示客户端的名称,参数 event 表示要发送的事件,参数 data 表示要发送的数据。

【例12.4】实现与好友聊天功能。(实例位置:资源包\源码\12\04)

本实例中模拟的是小B(第一个客户端)与两个好友(后面两个客户端)的聊天过程。具体步骤如下。

(1) 在 WebStorm 中创建一个 js.js 文件,该文件中的 only 事件中的数据是其他好友向小 B 单独发送的内容,而 all 事件中的数据为群发的内容。服务器向客户端发送的事件有 toOnetoMany,它们分别将单独发送的内容和群发的内容发送至客户端。js.js 文件中的代码如下:

//引入模块
var http = require('http');
var fs = require('fs');
var socketio = require('socket.io');
//创建Web服务器
var server = http.createServer(function (request, response) {
     //读取index.html
     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');
});
//创建列表,用来记录连接的客户端
var list=[]
//创建WebSocket服务器
var io = socketio(server);
io.sockets.on('connection', function (socket) {
     list.push(socket.id)                            //有客户端连接时,将其id保存到列表中
     socket.on("only",function(data){
               io.to(list[0]).emit('toOne', data)    //向指定客户端发送private类型消息
     })
     socket.on("all",function(data){
          io.sockets.emit("toMany",data)
     })
})

(2) 新建客户端页面 index.html,该页面中使用 socket.on() 方法监听 toOnetoMany 事件,并将这两个事件中附带的消息内容显示在网页中。代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        label {
            display: block;
            width: 230px;
            margin: 10px auto;
        }
        .bold {
            font-weight: bold;
            color: red;
        }
        ul {
            list-style: none;
        }
    </style>
    <script src="/socket.io/socket.io.js"></script>
</head>
<body>
<form action="">
    <fieldset style="width: 360px;margin: 0 auto">
        <legend>发送消息</legend>
        <label>内容:<input id="text" type="text"><br></label>
        <div id="sendTo">
            <button id="btn" type="button">群发</button>
            <button id="btnB" type="button">发送给小B</button>
        </div>
    </fieldset>
    <ul id="box"></ul>
</form>
<script>
    window.onload = function () {
        var box = document.getElementById("box")
        var sendTo = document.getElementById("sendTo")
        const socket = io.connect()
        socket.on("toOne", function (data) {    //显示接收到的私信内容
            var html1 = "<span>收到一条私信:</span>"
            html1 += "<span class='bold'>" + data + "</span>"
            var li = document.createElement("li")
            li.innerHTML += html1
            box.append(li)
        })
        socket.on("toMany",function(data){   //显示群发内容
            var html1 = "<span>收到一条群发消息:</span>"
            html1 += "<span class='bold'>" + data + "</span>"
            var li = document.createElement("li")
            li.innerHTML += html1
            box.append(li)
        })
        document.getElementById("btn").onclick = function () {
            var text = document.getElementById("text").value
                socket.emit("all", text)    //群发消息
        }
        document.getElementById("btnB").onclick = function () {
            var text = document.getElementById("text").value
            socket.emit("only", text)     //私发消息
        }
    }
</script>
</body>
</html>

运行 js.js 文件,3 次打开 http://127.0.0.1:52273 网页地址(按打开顺序,第一个为 “小B” 客户端),此时打开的 3 个网页的效果都如图 12.18 所示。

image 2024 04 17 11 40 37 773
Figure 9. 图12.18 浏览器中初始运行效果

分别在 3 个浏览器中模拟与好友聊天,效果如图12.19所示。

image 2024 04 17 11 41 10 774
Figure 10. 图12.19 好友聊天效果图

使用 socket 发送 private 类型的信息时,如果使用的是 socket.io 1.0 及之前的版本,则需要使用 io.sockets.to(id).emit() 方法。