概述
WebSockets是一种在浏览器和服务器之间建立持久连接的协议,它允许服务器主动推送数据给客户端,并且在客户端和服务器之间实现双向通信。
-
建立连接:客户端通过在JavaScript代码中使用WebSocket对象来建立WebSockets连接。例如:
var socket = new WebSocket('ws://example.com/socket');
-
协议:WebSockets使用标准的WebSocket协议来进行通信。相对于HTTP协议,WebSocket协议提供了更高效率和更低的延迟。ws和wss协议正对应了http和https。
-
服务器支持:为了使用WebSockets,服务器必须支持WebSocket协议。
-
事件:WebSocket对象提供了一些事件,用于处理连接的不同阶段和接收到的数据。常见的事件有
onopen
(连接建立)、onmessage
(接收到消息)、onclose
(连接关闭)等。 -
数据传输:WebSockets可以传输文本和二进制数据。文本数据是以UTF-8编码发送和接收的,而二进制数据使用ArrayBuffer对象。
-
安全性:与HTTP协议通过TLS/SSL协议进行加密一样,WebSockets也可以通过wss协议来提供安全的通信。wss://表示通过TLS/SSL加密的WebSockets连接。
-
跨域策略:WebSockets默认不受同源策略的限制,可以跨域使用,但仍然会受到服务器的安全策略限制。
可以在浏览器和服务器之间建立稳定的连接,实际应用如聊天应用、实时数据监控等。
基本使用
使用WebSockets进行连接和通信:
首先,在客户端使用WebSocket对象来建立连接:
var socket = new WebSocket('ws://example.com/socket');// 监听连接建立事件
socket.onopen = function() {console.log('WebSocket连接已建立');// 向服务器发送消息socket.send('Hello Server!');
};// 监听接收到消息事件
socket.onmessage = function(event) {var message = event.data;console.log('接收到服务器消息:' + message);
};// 监听连接关闭事件
socket.onclose = function() {console.log('WebSocket连接已关闭');
};
在上面的代码中,我们创建了一个WebSocket对象并指定连接的URL。然后我们监听了三个事件:onopen
表示连接建立时触发的事件,onmessage
表示接收到消息时触发的事件,onclose
表示连接关闭时触发的事件。
在连接建立后,我们向服务器发送了一条消息Hello Server!
。当服务器向客户端发送消息时,onmessage
事件将被触发,并且我们可以在回调函数中处理接收到的消息。
接下来,让我们看一下服务器端的示例代码(以Node.js和Express框架为例):
const express = require('express');
const WebSocket = require('ws');const app = express();// 创建WebSocket服务器
const server = require('http').createServer(app);
const wss = new WebSocket.Server({ server });wss.on('connection', function(socket) {console.log('WebSocket连接已建立');// 监听客户端发送的消息socket.on('message', function(message) {console.log('接收到客户端消息:' + message);// 向客户端发送消息socket.send('Hello Client!');});// 监听连接关闭事件socket.on('close', function() {console.log('WebSocket连接已关闭');});
});server.listen(3000, function() {console.log('服务器已启动,监听端口3000');
});
在服务器端的代码中,我们使用了ws库创建了一个WebSocket服务器,并监听了connection
事件。当有客户端连接到服务器时,connection
事件将被触发,并在该回调函数中处理连接过程。
在服务器接收到客户端的消息时,我们输出消息到控制台,并向客户端发送一条回复消息。当连接关闭时,close
事件将被触发。
最后,我们在Express应用中创建了一个HTTP服务器,将WebSocket服务器绑定到服务器上,然后启动服务器监听端口3000。
通信小实例
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<script>const ws = new WebSocket('ws://localhost:3000')ws.addEventListener('open',()=> {console.log('已连接服务器')ws.send('我是前端的数据')})ws.addEventListener('message', ({data})=> {console.log(data)})
</script>
</body>
</html>
const WebSocket = require('ws')
const socket = new WebSocket.Server({port: 3000});socket.on('connection',ws=> {console.log('我进来了')ws.on('message',(data)=> {console.log('前端数据:' + data + "。后端返回数据:"+ '我是后端的数据')})ws.on('close',()=> {console.log('溜了溜了')})
})
Socket.io
Socket.io 具有跨平台,实时性,WebSocket 不可连接时自动降级到其他传播机制(如 http 长轮询)等优点。
官方文档:(服务器初始化 | Socket.IO)
npm install socket.io
安装。
聊天室案例
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>* {padding: 0;margin: 0;}html,body,.room {height: 100%;width: 100%;}.room {display: flex;}.left {width: 300px;border-right: 0.5px solid #2b2d30;background: #333;}.right {background: #1c1c1c;flex: 1;display: flex;flex-direction: column;}.header {background: rgb(60, 63, 65);color: white;padding: 10px;box-sizing: border-box;font-size: 20px;}.main {flex: 1;padding: 10px;box-sizing: border-box;font-size: 20px;overflow: auto;}.main-chat {color: #bcbec4;}.footer {min-height: 200px;border-top: 1px solid #4e5157;}.footer .ipt {width: 100%;height: 100%;color: #bcbec4;outline: none;font-size: 20px;padding: 10px;box-sizing: border-box;}.groupList {height: 100%;overflow: auto;}.groupList-items {height: 50px;width: 100%;background: rgb(67, 69, 74);border-bottom: 1px solid #2b2d30;display: flex;align-items: center;justify-content: center;color: white;}</style>
</head>
<div class="room"><div class="left"><div class="groupList"></div></div><div class="right"><header class="header">聊天室</header><main class="main"></main><footer class="footer"><div class="ipt" contenteditable></div></footer></div>
</div><body>
<script type="module">import {io} from "https://cdn.socket.io/4.7.4/socket.io.esm.min.js";let name = prompt('请输入你的名字')let room = prompt('请输入你要进入的房间')const sendMessage = (message) => {const div = document.createElement('div');div.className = 'main-chat';div.innerText = `${message.user}:${message.text}`;main.appendChild(div)}const group = document.querySelector('.groupList'); // 左侧列表的父级const main = document.querySelector('.main'); // 消息内容的父级const ipt = document.querySelector('.footer .ipt')// 希望自己也能收到信息const addChart = (msg)=> {let item = document.createElement('div')item.className = 'main-chat'item.innerHTML = `${msg.name}: ${msg.message}`main.appendChild(item)}const socket = io('ws://localhost:3000') // ws 的地址socket.on('connect', () => {// 监听回车事件document.addEventListener('keydown',e=> {if (e.key === 'Enter') {const message = ipt.innerTextsocket.emit('message', {name, message, room})addChart({name, message})ipt.innerText = ''}})// 加入房间socket.emit('join', {name, room})//监听左侧列表socket.on('groupMap', (data) => {group.innerHTML = ``Object.keys(data).forEach(key=> {const item = document.createElement('div')item.className = 'groupList-items'item.innerHTML = `房间号:${key} 房间人数:${data[key].length}`group.appendChild(item)})})//监听发送的消息socket.on('message', (data) => {addChart(data)})})
</script>
</body></html>
import {createServer} from "http";
import {Server} from "socket.io";const server = createServer();
const io = new Server(server, {cors: true // 允许跨域
});
/*** [{name, room, id}, {name, room, id}]* @type {{}}*/
const groupMap = {}io.on("connection", (socket) => {// 前端传过来 name 和 roomsocket.on('join', ({name, room}) => {socket.join(room) // 创建一个房间if (groupMap[room]) {groupMap[room].push({name, room, id: socket.id}) // 已有就 push} else {groupMap[room] = [{name, room, id: socket.id}] // 没有就创建}socket.emit('groupMap', groupMap)// 所有人都可以看到socket.broadcast.emit('groupMap', groupMap)// 管理员发送信息socket.broadcast.to(room).emit('message', {name: '管理员',message: `欢迎${name}进入聊天室`})})// 向前端发消息socket.on('message', ({name, message, room}) => {// 虽然给别人发送了消息,但是自己收不到socket.broadcast.to(room).emit('message', {name, message})})
});server.listen(3000);