WebSocket 通信
HTTP 的局限
HTTP 是无状态的,服务器无法主动向客户端推送数据。传统轮询方案效率低(每次请求包含完整头部,有效数据占比小)。
WebSocket 简介
WebSocket 实现客户端与服务端的双向通信,适用于:
- 社交订阅 / 即时聊天
- 多玩家游戏
- 协同编辑
- 股票 / 基金实时报价
- 在线教育
搭建 WebSocket 服务器
使用 socket.io:
bash
npm install socket.ionpm install socket.iojs
const express = require('express')
const app = express()
const server = require('http').createServer(app)
const io = require('socket.io')(server)
io.on('connection', (socket) => {
console.log('客户端已连接')
})
// 必须用 server 监听,不能用 app.listen
server.listen(3000)const express = require('express')
const app = express()
const server = require('http').createServer(app)
const io = require('socket.io')(server)
io.on('connection', (socket) => {
console.log('客户端已连接')
})
// 必须用 server 监听,不能用 app.listen
server.listen(3000)客户端引入 /socket.io/socket.io.js(自动生成)。
消息发送
js
// 只发送给自己
socket.emit('message', data)
// 发送给除自己外的所有人
socket.broadcast.emit('message', data)
// 发送给所有人(包括自己)
io.emit('message', data)// 只发送给自己
socket.emit('message', data)
// 发送给除自己外的所有人
socket.broadcast.emit('message', data)
// 发送给所有人(包括自己)
io.emit('message', data)示例
js
// 服务端
io.on('connection', (socket) => {
socket.on('chat', (data) => {
io.emit('chat', data) // 广播给所有人
})
})
// 客户端
const socket = io()
socket.emit('chat', 'Hello')
socket.on('chat', (data) => {
console.log('收到:', data)
})// 服务端
io.on('connection', (socket) => {
socket.on('chat', (data) => {
io.emit('chat', data) // 广播给所有人
})
})
// 客户端
const socket = io()
socket.emit('chat', 'Hello')
socket.on('chat', (data) => {
console.log('收到:', data)
})房间管理
js
io.on('connection', (socket) => {
// 加入房间
socket.on('subscribe', (data) => {
socket.join(data.room)
io.to(data.room).emit('some event')
})
// 加入多个房间
socket.to('room1').to('room2').emit('hello')
// 离开房间
socket.on('unsubscribe', (data) => {
socket.leave(data.room)
})
// 房间内广播(不包括发送者)
socket.broadcast.to('roomA').emit('message', '大家好')
// 房间内广播(包括发送者)
io.sockets.in('roomA').emit('message', '大家好')
})io.on('connection', (socket) => {
// 加入房间
socket.on('subscribe', (data) => {
socket.join(data.room)
io.to(data.room).emit('some event')
})
// 加入多个房间
socket.to('room1').to('room2').emit('hello')
// 离开房间
socket.on('unsubscribe', (data) => {
socket.leave(data.room)
})
// 房间内广播(不包括发送者)
socket.broadcast.to('roomA').emit('message', '大家好')
// 房间内广播(包括发送者)
io.sockets.in('roomA').emit('message', '大家好')
})断开连接
js
io.on('connection', (socket) => {
socket.on('disconnect', (reason) => {
console.log('用户断开连接:', reason)
})
})io.on('connection', (socket) => {
socket.on('disconnect', (reason) => {
console.log('用户断开连接:', reason)
})
})在线人数统计
js
let onlineUsers = {}
let i = 0
io.on('connection', (socket) => {
socket.name = ++i
onlineUsers[socket.name] = socket
socket.on('disconnect', () => {
delete onlineUsers[socket.name]
})
socket.on('/user/list', (callback) => {
callback(Object.keys(onlineUsers).length)
})
})let onlineUsers = {}
let i = 0
io.on('connection', (socket) => {
socket.name = ++i
onlineUsers[socket.name] = socket
socket.on('disconnect', () => {
delete onlineUsers[socket.name]
})
socket.on('/user/list', (callback) => {
callback(Object.keys(onlineUsers).length)
})
})React 中使用
jsx
import IO from 'socket.io-client'
const socket = IO('ws://localhost:3006', {
transports: ['websocket']
})
socket.on('connect', () => {
console.log('已连接', socket.connected)
})
socket.on('connect_error', (error) => {
console.log('连接错误', error)
})
// 页面关闭时断开连接
socket.close()import IO from 'socket.io-client'
const socket = IO('ws://localhost:3006', {
transports: ['websocket']
})
socket.on('connect', () => {
console.log('已连接', socket.connected)
})
socket.on('connect_error', (error) => {
console.log('连接错误', error)
})
// 页面关闭时断开连接
socket.close()完整聊天室示例
js
// 服务端
io.on('connection', (socket) => {
socket.on('message', (msg) => {
io.emit('message', msg)
})
socket.on('/user/list', (callback) => {
callback('success')
})
socket.on('user/modify', (name, callback) => {
user.name = name
callback('修改成功')
})
})
// 客户端
socket.emit('message', '您好')
socket.emit('/user/list', (list) => {})
socket.emit('user/modify', 'hny', (result) => {})// 服务端
io.on('connection', (socket) => {
socket.on('message', (msg) => {
io.emit('message', msg)
})
socket.on('/user/list', (callback) => {
callback('success')
})
socket.on('user/modify', (name, callback) => {
user.name = name
callback('修改成功')
})
})
// 客户端
socket.emit('message', '您好')
socket.emit('/user/list', (list) => {})
socket.emit('user/modify', 'hny', (result) => {})
Cao Note