使用 ServBay 创建和运行 Socket.io 项目
Socket.io 是一个流行的 JavaScript 库,专为构建实时、双向、事件驱动的 Web 应用程序而设计。它基于 WebSocket 协议,并在必要时提供回退机制(如长轮询),确保在各种客户端和网络条件下都能实现稳定可靠的实时通信。
本指南将详细介绍如何利用 ServBay 强大的本地开发环境来搭建、运行和管理一个 Socket.io 项目。ServBay 提供预配置的 Node.js 环境以及便捷的网站(原称:主机)管理功能,使 Socket.io 开发变得更加高效。
什么是 Socket.io?
Socket.io 是一个实现了实时、双向、基于事件的通信机制的库。它由两个部分组成:
- 一个运行在 Node.js 服务器上的后端库。
- 一个运行在浏览器中的客户端 JavaScript 库。
尽管 Socket.io 的主要目标是使用 WebSocket,但它通过自动检测和回退到其他传输方式(如 Adobe Flash Socket、Ajax Long Polling、Ajax Multipart Streaming、Forever IFrame、JSONP Polling 等)来保证在不支持 WebSocket 的旧浏览器或受限网络环境中的兼容性。
Socket.io 的主要特性和优势
- 实时通信: 实现服务器和客户端之间的即时数据交换,非常适合构建聊天应用、协作工具、实时仪表盘、在线游戏等。
- 跨平台支持: 可以在 Web 浏览器、移动端应用以及 Node.js 服务器环境中使用。
- 自动重连: 在网络连接中断后,客户端会自动尝试重新连接到服务器,提高了应用的健壮性。
- 事件驱动: 基于事件的编程模型使得处理异步通信变得直观和易于管理。
- 房间和命名空间: 支持将客户端分组到“房间”中,以便向特定组广播消息;“命名空间”则允许在同一个连接上复用资源并实现多路复用。
- 二进制支持: 可以方便地发送和接收二进制数据。
- 高兼容性: 通过多种传输机制确保在各种网络条件下的可靠性。
借助 Socket.io,开发者可以专注于应用逻辑,而不必过多关注底层复杂的实时通信实现细节。
使用 ServBay 创建并运行 Socket.io 项目
ServBay 为 Node.js 开发者提供了一个开箱即用的本地环境,包括 Node.js 运行时、npm 包管理器以及方便的网站管理工具。我们将利用这些功能来设置和运行我们的 Socket.io 示例项目。
前提条件
在开始之前,请确保您已经完成以下准备工作:
- 安装 ServBay: 从 ServBay 官方网站 下载并安装最新版本的 ServBay。
- 在 ServBay 中安装 Node.js 软件包: 确保您已经在 ServBay 中安装了 Node.js 软件包。您可以通过 ServBay 控制面板的“软件包”(原称:服务)部分进行安装和管理。请参考 在 ServBay 中使用 Node.js 文档获取更详细的安装和使用指南。
创建 Socket.io 示例项目
我们将创建一个简单的聊天应用作为示例。
初始化项目目录:
首先,打开您的终端应用程序。ServBay 建议将网站项目存放在
/Applications/ServBay/www目录下。进入该目录并创建一个新的项目文件夹,然后初始化 Node.js 项目并安装必要的依赖:bashcd /Applications/ServBay/www mkdir servbay-socketio-chat cd servbay-socketio-chat npm init -y npm install express socket.io1
2
3
4
5这将在
servbay-socketio-chat文件夹中创建一个package.json文件,并安装express(用于提供静态文件和处理 HTTP 请求)和socket.io(服务器和客户端库)这两个核心依赖。创建服务器文件 (
server.js):在
servbay-socketio-chat项目根目录下创建一个名为server.js的文件,并复制粘贴以下代码。此文件将负责启动 HTTP 服务器、集成 Socket.io,并处理客户端的连接和消息广播。javascriptconst express = require('express'); const http = require('http'); const socketIo = require('socket.io'); const path = require('path'); // 引入 path 模块 const app = express(); // 创建一个基于 express 应用的 HTTP 服务器 const server = http.createServer(app); // 将 Socket.io 附加到 HTTP 服务器 const io = socketIo(server); // 设置静态文件目录,指向当前目录 app.use(express.static(__dirname)); // 处理根路径的 GET 请求,发送 index.html 文件 app.get('/', (req, res) => { // 使用 path.join 确保路径在不同操作系统下都能正确工作 res.sendFile(path.join(__dirname, 'index.html')); }); // 监听 Socket.io 连接事件 io.on('connection', (socket) => { console.log('a user connected'); // 当有新用户连接时打印日志 // 监听断开连接事件 socket.on('disconnect', () => { console.log('user disconnected'); // 当用户断开连接时打印日志 }); // 监听 'chat message' 事件 socket.on('chat message', (msg) => { console.log('message: ' + msg); // 打印收到的消息 // 将收到的消息广播给所有连接的客户端 io.emit('chat message', msg); }); }); // 从环境变量或默认值获取端口号 const port = process.env.PORT || 3000; server.listen(port, () => { console.log(`Server running on port ${port}`); console.log(`Access it via http://localhost:${port} (direct) or via ServBay reverse proxy`); });1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43代码说明:
- 我们使用了
express来创建一个简单的 Web 服务器,用于提供index.html文件。 http.createServer(app)创建了一个标准的 HTTP 服务器,这是 Socket.io 附加的基础。socketIo(server)初始化了 Socket.io 并将其绑定到 HTTP 服务器上。io.on('connection', ...)监听新的客户端连接。socket.on('disconnect', ...)监听客户端断开连接。socket.on('chat message', ...)监听客户端发送的名为'chat message'的事件,并接收消息数据。io.emit('chat message', msg)将收到的消息广播给 所有 当前连接的客户端。
- 我们使用了
创建客户端文件 (
index.html):在
servbay-socketio-chat项目根目录下创建一个名为index.html的文件,并复制粘贴以下代码。此文件包含客户端 HTML 结构、样式以及 Socket.io 客户端 JavaScript 代码,用于连接服务器、发送消息和显示接收到的消息。html<!DOCTYPE html> <html> <head> <title>ServBay Socket.io Chat</title> <style> body { margin: 0; padding-bottom: 3rem; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; } #form { background: rgba(0, 0, 0, 0.15); padding: 0.25rem; position: fixed; bottom: 0; left: 0; right: 0; display: flex; height: 3rem; box-sizing: border-box; backdrop-filter: blur(10px); } #input { border: none; padding: 0 1rem; flex-grow: 1; border-radius: 2rem; margin: 0.25rem; } #input:focus { outline: none; } #form > button { background: #333; border: none; padding: 0 1rem; margin: 0.25rem; border-radius: 3px; outline: none; color: #fff; } #messages { list-style-type: none; margin: 0; padding: 0; } #messages > li { padding: 0.5rem 1rem; } #messages > li:nth-child(odd) { background: #efefef; } .servbay-banner { background-color: #007bff; /* ServBay Blue */ color: white; text-align: center; padding: 15px 0; font-size: 22px; margin-bottom: 20px; font-weight: bold; } </style> </head> <body> <div class="servbay-banner">Welcome to ServBay Socket.io Chat Demo!</div> <ul id="messages"></ul> <form id="form" action=""> <input id="input" autocomplete="off" /><button type="submit">Send</button> </form> <!-- 引入 Socket.io 客户端库 --> <!-- 这个文件是 Socket.io 服务器端在运行时动态生成的 --> <script src="/socket.io/socket.io.js"></script> <script> // 连接到 Socket.io 服务器 // 如果客户端和服务器运行在同一个域名和端口,io() 会自动连接 var socket = io(); var form = document.getElementById('form'); var input = document.getElementById('input'); var messages = document.getElementById('messages'); // 获取 messages 元素 form.addEventListener('submit', function(e) { e.preventDefault(); // 阻止表单默认提交行为 if (input.value) { // 发送 'chat message' 事件和消息内容到服务器 socket.emit('chat message', input.value); input.value = ''; // 清空输入框 } }); // 监听服务器发送的 'chat message' 事件 socket.on('chat message', function(msg) { // 创建新的列表项显示消息 var item = document.createElement('li'); item.textContent = msg; // 使用 textContent 防止 XSS 攻击 messages.appendChild(item); // 将消息添加到列表中 // 滚动到最新消息 window.scrollTo(0, document.body.scrollHeight); }); </script> </body> </html>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64代码说明:
- 页面包含一个简单的 HTML 结构、一些 CSS 样式(包括 ServBay 品牌色的横幅)、一个消息列表 (
ul#messages) 和一个发送消息的表单 (form#form)。 <script src="/socket.io/socket.io.js"></script>引入了 Socket.io 客户端库。注意,这个文件不是我们自己创建的,而是 Socket.io 服务器在启动时自动在/socket.io/socket.io.js路径下提供的。io()初始化并连接到 Socket.io 服务器。- 客户端监听表单的提交事件,阻止默认行为,然后通过
socket.emit('chat message', input.value)将消息发送到服务器。 - 客户端监听服务器发来的
'chat message'事件,并将其添加到页面上的消息列表中。
- 页面包含一个简单的 HTML 结构、一些 CSS 样式(包括 ServBay 品牌色的横幅)、一个消息列表 (
至此,您已经完成了 Socket.io 示例项目的基本代码编写。接下来,我们将使用 ServBay 来运行和访问它。
通过 ServBay 运行项目 (开发模式)
在开发阶段,我们通常直接运行 Node.js 服务器,然后通过 ServBay 的反向代理功能将其映射到本地域名。
启动 Node.js 开发服务器:
打开终端,进入项目目录
/Applications/ServBay/www/servbay-socketio-chat,并运行以下命令启动服务器。我们指定端口为 8585,您可以根据需要更改。bashcd /Applications/ServBay/www/servbay-socketio-chat PORT=8585 node server.js1
2服务器启动后,您将在终端看到类似
Server running on port 8585的输出。此时,服务器正在监听本地的 8585 端口。在 ServBay 中配置网站 (反向代理):
为了方便通过本地域名访问,并利用 ServBay 的 HTTPS/SSL 功能,我们将在 ServBay 中创建一个反向代理网站。
- 打开 ServBay 控制面板。
- 导航到“网站”(原称:主机)部分。
- 点击添加新网站的按钮。
- 配置如下:
- 名字 (Name):
ServBay Socket.io Dev(或其他易于识别的名称) - 域名 (Domains):
servbay-socketio-dev.servbay.demo(或其他.servbay.demo域名) - 网站类型 (Type): 选择
反向代理 (Reverse Proxy) - 代理目标 (Proxy Destination): 输入
http://127.0.0.1:8585(指向您刚刚启动的 Node.js 服务器地址和端口)
- 名字 (Name):
- 保存配置。ServBay 将自动应用更改并可能需要重启相关的 Web 服务器(如 Caddy 或 Nginx,具体取决于您的 ServBay 配置)。
注意: 反向代理对于 Socket.io 至关重要,因为它不仅转发标准的 HTTP 请求,还会处理 WebSocket 协议的升级握手。ServBay 内置的 Caddy 或 Nginx 配置已经包含了对 WebSocket 代理的支持。
有关在 ServBay 中添加网站的详细步骤,请参考 添加 Node.js 开发网站 文档。您还可以通过 ServBay 为此本地域名启用 HTTPS,请参考 使用 SSL/TLS 保护网站 文档。ServBay User CA 和 ServBay Public CA 都可以用于生成和信任本地 SSL 证书。
访问开发模式网站:
在浏览器中打开您配置的本地域名
https://servbay-socketio-dev.servbay.demo。您应该能看到聊天界面,并且可以在不同浏览器标签页或设备上打开该地址进行实时聊天测试。
通过 ServBay 部署项目 (生产模式)
对于生产环境,您可能希望以更健壮的方式运行 Node.js 应用(例如使用 PM2 或 forever 等进程管理器),并将其与 ServBay 集成。这里我们仅演示 ServBay 反向代理部分的配置,假设您的 Node.js 应用已在后台稳定运行于某个端口。
启动 Node.js 生产服务器:
在生产环境中,您通常会使用进程管理器启动 Node.js 应用,以确保它在崩溃时自动重启并在后台运行。例如,使用 PM2:
bash# 如果未安装 PM2 # npm install pm2 -g cd /Applications/ServBay/www/servbay-socketio-chat PORT=8586 NODE_ENV=production pm2 start server.js --name servbay-socketio-prod1
2
3
4
5这将使用 PM2 启动
server.js,指定端口为 8586,并设置环境变量NODE_ENV为production。进程管理器会确保应用在后台运行。在 ServBay 中配置生产网站 (反向代理):
类似开发模式,在 ServBay 中创建一个新的反向代理网站指向生产环境运行的 Node.js 端口。
- 打开 ServBay 控制面板。
- 导航到“网站”部分。
- 点击添加新网站的按钮。
- 配置如下:
- 名字 (Name):
ServBay Socket.io Prod(或其他易于识别的名称) - 域名 (Domains):
servbay-socketio-prod.servbay.demo(或其他.servbay.demo域名) - 网站类型 (Type): 选择
反向代理 (Reverse Proxy) - 代理目标 (Proxy Destination): 输入
http://127.0.0.1:8586(指向您生产模式下运行的 Node.js 服务器端口)
- 名字 (Name):
- 保存配置。
访问生产模式网站:
在浏览器中打开您配置的生产模式本地域名
https://servbay-socketio-prod.servbay.demo。
通过 ServBay 的反向代理功能,您可以方便地管理多个 Node.js 应用(无论开发或生产模式),为它们配置本地域名和 SSL 证书,而无需手动修改系统 hosts 文件或管理复杂的 Web 服务器配置。
连接 ServBay 提供的数据库
ServBay 支持多种数据库软件包,包括 MySQL、MariaDB、PostgreSQL、MongoDB 和 Redis。您的 Socket.io 应用可能需要与这些数据库交互来存储用户数据、消息历史等。以下是连接这些数据库的 Node.js 代码示例。
重要: 在运行以下代码之前,请确保您已通过 ServBay 控制面板安装并启动了相应的数据库软件包。数据库的默认连接信息(如端口、默认用户和密码)可以在 ServBay 的数据库管理界面或相关文档中找到。例如,MySQL/MariaDB 的 root 用户默认密码通常是 ServBay 安装时设置的。您也可以通过 ServBay 的功能重置数据库 root 密码。
连接 MongoDB:
安装 Mongoose ODM (或官方
mongodb驱动):bashnpm install mongoose1在您的 Node.js 代码中(例如
server.js或单独的数据库模块)添加连接逻辑:javascriptconst mongoose = require('mongoose'); // 默认连接到本地运行的 MongoDB 实例 (端口 27017 是 MongoDB 默认端口) // 数据库名称 servbay_socketio_app 是示例 mongoose.connect('mongodb://localhost:27017/servbay_socketio_app', { useNewUrlParser: true, useUnifiedTopology: true, // 其他选项如 user, pass 如果需要认证 // user: 'your_mongo_user', // pass: 'your_mongo_password' }) .then(() => console.log('MongoDB connected successfully via Mongoose')) .catch(err => console.error('MongoDB connection error:', err)); // 您现在可以使用 mongoose.model() 来定义 Schema 和 Model // ...1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16连接 Redis:
安装
redis客户端库:bashnpm install redis1在您的 Node.js 代码中添加连接逻辑:
javascriptconst redis = require('redis'); // 创建 Redis 客户端实例,默认连接到 localhost:6379 (Redis 默认端口) const client = redis.createClient({ // 如果 Redis 需要密码认证 // password: 'your_redis_password', // url: 'redis://localhost:6379' // 或者使用 URL 格式 }); client.on('error', (err) => { console.error('Redis connection error:', err); }); client.on('connect', () => { console.log('Redis client connected successfully'); }); // 连接到 Redis 服务器 client.connect(); // 对于 v4+ 版本,需要显式调用 connect() // 您现在可以使用 client 对象执行 Redis 命令 // 例如: await client.set('mykey', 'myvalue'); // ...1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23连接 MariaDB / MySQL:
ServBay 同时支持 MariaDB 和 MySQL。连接方式类似。我们使用
mariadb库作为示例 (它也兼容 MySQL)。安装
mariadb客户端库:bashnpm install mariadb1在您的 Node.js 代码中添加连接逻辑:
javascriptconst mariadb = require('mariadb'); // 创建连接池 const pool = mariadb.createPool({ host: 'localhost', port: 3306, // MariaDB/MySQL 默认端口 user: 'root', // ServBay 默认用户通常是 root password: 'password', // 使用您 ServBay 中为 root 设置的密码 database: 'servbay_socketio_app', // 示例数据库名称 connectionLimit: 5 // 连接池大小 }); // 从连接池获取连接并测试 pool.getConnection() .then(conn => { console.log("Connected to MariaDB/MySQL successfully"); conn.release(); // 释放连接回连接池 // 您现在可以使用 pool 对象执行数据库查询 // 例如: await pool.query("SELECT 1"); // ... }) .catch(err => { console.error("MariaDB/MySQL connection error:", err); });1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24注意: 请将
password替换为您在 ServBay 中为 MariaDB/MySQL root 用户设置的实际密码。建议为应用创建专门的数据库用户,而不是直接使用 root 用户。连接 PostgreSQL:
安装
pg客户端库:bashnpm install pg1在您的 Node.js 代码中添加连接逻辑:
javascriptconst { Pool } = require('pg'); // 创建连接池 const pool = new Pool({ user: 'user', // PostgreSQL 默认用户通常是 user host: 'localhost', database: 'servbay_socketio_app', // 示例数据库名称 password: 'password', // 使用您 ServBay 中为 PostgreSQL 设置的密码 port: 5432, // PostgreSQL 默认端口 }); // 从连接池获取连接并测试 pool.connect((err, client, done) => { if (err) { console.error('PostgreSQL connection error:', err); return; } console.log('Connected to PostgreSQL successfully'); client.release(); // 释放连接回连接池 // 您现在可以使用 pool 对象执行数据库查询 // 例如: pool.query('SELECT NOW()', (err, res) => { ... }); // ... });1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23注意: 请将
user和password替换为您在 ServBay 中为 PostgreSQL 设置的实际用户和密码。
通过集成这些数据库,您的 Socket.io 应用可以持久化数据,构建更复杂的功能。ServBay 使得在本地快速搭建包含 Node.js 和各种数据库的开发环境变得非常便捷。
注意事项
- 端口冲突: 确保您的 Node.js 应用监听的端口(示例中的 8585 或 8586)没有被其他应用程序占用。如果端口冲突,您可以更改
PORT环境变量的值。 - ServBay 网站配置: 在 ServBay 中配置反向代理网站后,请确保 ServBay 的 Web 服务器(Caddy 或 Nginx)已成功重启并应用了新的配置。
- WebSocket 代理: ServBay 的反向代理配置默认支持 WebSocket 协议的升级。如果遇到 WebSocket 连接问题,请检查 ServBay 的 Web 服务器日志或配置,确保 WebSocket 代理设置正确。
- 防火墙: 确保您的操作系统防火墙没有阻止对 ServBay 使用的端口(如 80, 443)或 Node.js 应用端口的访问。
