WebSocket 与 HTTP 的不同 - 聊天室实战
WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。它与 HTTP 有着本质的不同,下面我们通过一个聊天室的实战来体验 WebSocket 的魅力。
初始化项目
首先,创建一个新的目录,并在该目录下运行 npm init
命令初始化项目:
npm init
安装 Express
Express 是一个基于 Node.js 的 Web 应用开发框架,使用下面的命令安装:
npm install express --save
--save
参数表示 Express 会作为生产依赖被安装,即在生产环境中也会使用到。
安装 nodemon
nodemon 是一个实用工具,它会监视项目中的文件,如果代码发生变化,会自动重启应用。使用下面的命令安装:
npm install nodemon --save-dev
--save-dev
参数表示 nodemon 会作为开发依赖被安装,只在开发环境中使用。
安装 socket.io
socket.io 是一个基于 WebSocket 的实时应用框架,它包括了客户端的 JavaScript 和服务器端的 Node.js。使用下面的命令安装:
npm install socket.io --save
配置 package.json
为了方便启动应用,我们可以在 package.json 中添加一个 npm 脚本:
{
"name": "websocket-chat",
"version": "1.0.0",
"description": "A chat room using WebSocket",
"main": "index.js",
"scripts": {
"start": "nodemon index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.17.3",
"socket.io": "^4.4.1"
},
"devDependencies": {
"nodemon": "^2.0.15"
}
}
现在,我们可以使用 npm start
命令来启动应用了。
聊天室实现
服务端
首先,创建 index.js
文件作为服务端入口:
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require('socket.io');
const io = new Server(server);
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('disconnect', () => {
console.log('user disconnected');
});
socket.on('chat message', (msg) => {
io.emit('chat message', msg);
});
});
server.listen(3000, () => {
console.log('listening on *:3000');
});
这段代码的主要功能:
- 创建一个 Express 应用,并将其传递给 HTTP 服务器
- 创建一个 Socket.IO 服务器,并将其附加到 HTTP 服务器上
- 为根路径
/
提供服务,返回index.html
文件 - 监听客户端连接事件
connection
,当有客户端连接时输出日志 - 监听客户端断开连接事件
disconnect
,当有客户端断开时输出日志 - 监听客户端发送的聊天消息事件
chat message
,将收到的消息广播给所有连接的客户端 - 启动 HTTP 服务器,监听 3000 端口
客户端
接下来,创建 index.html
文件作为客户端页面:
<!DOCTYPE html>
<html>
<head>
<title>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;
}
</style>
</head>
<body>
<ul id="messages"></ul>
<form id="form" action=""><input id="input" autocomplete="off" /><button>Send</button></form>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
var messages = document.getElementById('messages');
var form = document.getElementById('form');
var input = document.getElementById('input');
form.addEventListener('submit', function (e) {
e.preventDefault();
if (input.value) {
socket.emit('chat message', input.value);
input.value = '';
}
});
socket.on('chat message', function (msg) {
var item = document.createElement('li');
item.textContent = msg;
messages.appendChild(item);
window.scrollTo(0, document.body.scrollHeight);
});
</script>
</body>
</html>
这段代码的主要功能:
- 引入 Socket.IO 客户端库
- 创建一个 Socket.IO 客户端实例,连接到服务器
- 获取消息列表元素、表单元素和输入框元素的引用
- 监听表单的提交事件,阻止默认行为,将输入框的内容发送给服务器,并清空输入框
- 监听服务器广播的聊天消息事件
chat message
,将收到的消息添加到消息列表中,并滚动到底部
现在,我们可以运行 npm start
启动服务器,然后在浏览器中访问 http://localhost:3000
,就可以看到聊天室页面了。打开多个页面,就可以互相发送消息了。
总结
通过这个简单的聊天室实战,我们可以看到 WebSocket 与 HTTP 的不同之处:
- WebSocket 是双向通信,服务器可以主动向客户端发送消息,而 HTTP 是单向的,只能由客户端发起请求
- WebSocket 是长连接,建立连接后可以保持通信,而 HTTP 是短连接,每次请求都需要重新建立连接
- WebSocket 更加实时,延迟更低,而 HTTP 有一定的延迟
- WebSocket 更加节省资源,不需要每次都传递完整的 HTTP 头
当然,WebSocket 也有一些局限性,比如不支持 HTTP 的一些特性,如 Cookie、HTTP 认证等。在实际应用中,需要根据具体需求选择合适的技术方案。
希望通过这个实战,能够帮助你更好地理解 WebSocket 的工作原理和使用方法。如果有任何问题,欢迎随时交流探讨。