WebSocket网络编程的基本实现

WebSocket 是从 HTML5 开始提供的一种浏览器与服务器间进行通信的网络技术。使用 WebSocket 时,浏览器和服务器只需要做一个握手的动作,然后浏览器和服务器之间就形成了一条快速通道,两者之间就可以直接进行数据的互相传送。

使用 socket.io 模块可以很方便地实现 WebSocket 网络编程,使用之前,首先需要通过 npm 包管理器进行下载和安装,命令如下:

npm install socket.io

上述命令默认下载的是 socket.io 模块的最新版本,如果要下载指定的版本,比如下载 1.x.x,在上述命令后面添加 @1 即可,即:

npm install socket.io@1

安装 socket.io 模块后,如果要在程序中使用,需要进行引入,代码如下:

var socketio = require('socket.io');

使用 socket.io 模块进行 WebSocket 网络编程时,通常需要 3 个步骤,依次为创建 WebScoket 服务器、创建 WebSocket 客户端、服务器端和客户端的通信,下面分别进行讲解。

WebSocket服务器端实现

创建 WebSocket 服务器时,首先需要借助 http 模块的 createServer() 方法创建一个 Web 服务器;然后导入 socket.io 模块,并在 WebSocket 服务器构造函数中传入创建的 Web 服务器,从而创建一个 WebSocket 服务器;最后监听 connection 事件,判断是否有客户端连接。

socket.io 模块可以监听的服务器端事件如表12.1所示。

image 2024 04 16 19 23 52 673
Figure 1. 表12.1 服务器端事件及说明

例如,下面代码中通过 http 模块创建了一个 Web 服务器,其中读取一个名称为 index.html 的客户端文件;然后使用 socket.io 模块创建一个 WebSocket 服务器,为 WebSocket 服务器设置 connection 监听事件,当用户在 WebSocket 客户端发起 socket 请求时,会触发该事件,监听是否有客户端连接。代码如下:

var fs = require("fs")
var http = require("http");
var server = http.createServer(function (req, res) {           //创建Web服务器
     if (req.url == "/") {
          //读取客户端文件
          fs.readFile("index.html", function (err, data) {
               res.end(data);
          });
     }
});
server.listen(52273, function (socket) {
     console.log("监听地址在:http://127.0.0.1:52273")
});
//创建WebSocket服务器
var io = require('socket.io');
io = io(server);
//监听客户端连接
io.sockets.on("connection", function (socket) {
     console.log("1个客户端连接了");
});

运行上面代码,效果如图12.1所示。

image 2024 04 16 19 25 14 300
Figure 2. 图12.1 WebSocket 服务器端的执行效果

由于上面示例中没有编写客户端代码,即没有客户端连接,因此控制台没有显示 “1个客户端连接了”。

WebSocket客户端实现

创建 WebSocket 客户端时,需要加载 socket.io 客户端代码文件,即 socket.io.js,然后通过 socket.io 模块中的全局对象 ioconnect() 方法来向服务器端发起连接请求。connect() 方法的语法格式如下:

io.connect(url)

参数 url 为可选参数,表示要连接的 WebSocket 服务器地址,其可以是 WebSocket 服务器的 http 完整地址,也可以是相对路径,如果省略,则表示默认连接当前路径。

例如,在 12.1.1 节的示例代码中,可以看到使用 http 模块创建的 Web 服务器中读取了一个 index.html 客户端文件,该文件中主要引入 socket.io.js 客户端代码文件,并使用全局对象 ioconnect() 方法向服务端发起连接请求。代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
     <meta charset="utf-8">
     <title>Document</title>
</head>
<body>
<h2 style="color:red;text-align: center;margin: 20px auto">我是你们朝思暮想的客户端index.html</h2>
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
<script type="text/javascript">
     var socket = io.connect();
</script>
</body>
</html>

编写完 index.html 客户端文件后,再次运行 12.1.1 节中编写的服务器端文件,并单击运行结果中的链接 http://127.0.0.1:52273 ,效果如图12.2所示。

此时,再次返回控制台,可看到控制台发生变化,效果如图12.3所示。

图12.3是连接一个客户端时控制台的运行效果,如果在浏览器中多次打开 http://127.0.0.1:52273 地址,会发现每打开一次,控制台就会显示一次 “1个客户端连接了”,图 12.4 为打开 3 个客户端网页时的控制台的效果。

image 2024 04 16 19 28 56 607
Figure 3. 图12.2 浏览器中运行效果
image 2024 04 16 19 29 19 916
Figure 4. 图12.3 控制台的运行效果
image 2024 04 16 19 29 39 894
Figure 5. 图12.4 打开3个客户端网页时的控制台的效果

上面代码中,在客户端文件中引入了一个 socket.io.js 文件,该文件是在使用 socket.io 模块时自动下载到项目中的。我们可以在启动 Web 服务器后,在浏览器的地址栏中输入地址 http://127.0.0.1:52273/socket.io/socket.io.js ,查看 socket.io.js 文件,图 12.5 为该文件中的部分内容。

image 2024 04 16 19 30 35 737
Figure 6. 图12.5 自动下载的 socket.io.js 文件

服务器端和客户端的通信

创建了服务器端和客户端以后,就可以在服务器端和客户端之间传输数据了。socket.io 模块使用事件的方式进行数据传输,其中,socket.io 可以监听的服务器端事件在 12.1.1 节已经介绍过,具体可参见表 12.1,而其可以监听的客户端事件如表 12.2 所示。

image 2024 04 16 19 31 17 002
Figure 7. 表12.2 客户端事件及说明

要实现监听和发送事件,同样使用 on() 方法和 emit() 方法,具体如下。

  • on():监听 socket 事件。

  • emit():发送 socket 事件。

【例12.1】实现服务器端与客户端之间的通信。(实例位置:资源包\源码\12\01)

本实例需要创建的文件有 js.js 文件(服务器端代码)和 index.html 文件(客户端代码)。具体步骤如下。

(1) 编写 js.js 文件,该文件中首先引入相关模块,然后创建 Web 服务器与 WebSocket 服务器,使用 on() 方法监听 connection 事件,在有客户端连接时,继续监听是否有客户端发送的 clientData 事件,该事件是客户端自定义的一个事件,如果监听到该事件,则输出客户端传输的数据,并使用 emit() 方法向客户端发送一个自定义的 serverData 事件。js.js 文件如下:

//引入模块
var http = require('http');
var fs = require('fs');
//创建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 = require('socket.io')(server);
io.sockets.on('connection', function (socket) {
     console.log('客户端已连接!');
     //监听客户端的事件clientData,该事件在客户端定义
     socket.on('clientData', function (data) {
          //显示客户端发来的数据
          console.log('客户端发来的数据是:', data);
          //向客户端发送serverData事件和数据
          socket.emit('serverData', "谢谢,同乐同乐");
     });
});

(2) 编写 index.html 文件,在该文件中生成 socket 对象,然后使用其 on() 方法监听服务器端发送的 serverData 事件,如果监听到,输出传输的数据;然后为按钮创建一个点击事件,该点击事件中,获取文本框中输入的文本内容,并使用 emit() 方法向服务器端发送一个自定义的 clientData 事件。index.html 文件中的代码如下:

<!DOCTYPE html>
<html>
<head>
     <meta charset="utf-8">
     <script src="/socket.io/socket.io.js"></script>
</head>
<body onload="start()">
<fieldset>
     <legend>发送消息</legend>
     <div><label for="text">发送内容:</label><input type="text" id="text"/></div>
     <div><input type="button" id="button" value="确定"/></div>
</fieldset>
</body>
<script>
     //向服务器端发起连接请求
     var socket = io.connect();
     function start() {
          //监听服务器端的事件和数据
          socket.on('serverData', function (data) {
               alert("来自服务器端的消息"+"\n" + data);
          });
          //创建表单点击事件
          document.getElementById('button').onclick = function () {
               //获取表单数据
               var text = document.getElementById('text').value;
               //向服务器端发送事件clientData和数据
               socket.emit('clientData', text);
          };
     };
</script>
</html>

运行 js.js 文件,初始效果如图 12.6 所示。

image 2024 04 16 23 30 45 385
Figure 8. 图12.6 WebSocket 服务器的执行效果

打开浏览器,在地址栏中输入 http://127.0.0.1:52273 ,并按 Enter 键,此时浏览器中将显示如图 12.7 所示的 index.html 客户端页面,而服务器端控制台中会显示客户端已连接,如图12.8所示。

image 2024 04 16 23 31 51 234
Figure 9. 图12.7 浏览器中显示的index.html客户端页面
image 2024 04 16 23 33 04 729
Figure 10. 图12.8 服务器端控制台显示客户端已连接

在浏览器中的文本框中输入 “你好”,并单击 “确定” 按钮,此时,会弹出对话框显示从服务器端发来的消息,同时服务器端控制台也会接收到从客户端发来的 “你好” 消息,如图 12.9 和图 12.10 所示。

image 2024 04 16 23 33 50 241
Figure 11. 图12.9 接收服务器端的消息
image 2024 04 16 23 34 12 521
Figure 12. 图12.10 接收客户端的消息