四种实时通信技术大揭秘
🚀 四种实时通信技术大揭秘
1. 短轮询 (Short Polling) - 急性子快递员 📮
比喻 :就像一个急性子的快递员,每隔几秒就敲门问:“有快递吗?有快递吗?”
流程图
客户端与服务器通过GET方式访问/api/status200并返回状态码OK(有数据/无数据),然后进行循环等待(每隔固定时间),直到客户端与服务器之间完成操作。
代码示例
// 短轮询实现
class ShortPolling {
constructor(url, interval = 5000) {
this.url = url
this.interval = interval
this.timer = null
}
start() {
this.timer = setInterval(async () => {
try {
const response = await fetch(this.url)
const data = await response.json()
console.log('**收到数据:**', data)
this.onData(data)
} catch (error) {
console.error('轮询失败:', error)
}
}, this.interval)
}
stop() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
}
onData(data) {
// 处理数据的回调
}
}
// 使用示例 - 监控无人机状态
const droneMonitor = new ShortPolling('/api/drone/status', 3000)
droneMonitor.onData = (data) => {
updateDroneStatus(data)
}
droneMonitor.start()
javascript

优缺点 :
- ✅ 简单易懂 ,实现简单
- ❌ 浪费资源 ,大量无效请求
- ❌ 延迟较高 ,实时性差
2. 长轮询 (Long Polling) - 耐心等待的服务员 🍽️
比喻 :像餐厅服务员,客人点餐后会耐心等在桌边,直到菜做好才离开。
流程图
客户端服务器通过GET请求连接至/api/longpoll以等待数据。 server will persistently maintain connectivity until data is received or timeout occurs. HTTP response status code 200 OK indicates that data will be returned immediately upon receipt. Once the current response result is obtained, the system will immediately initiate the next request via GET /api/longpoll to continue waiting for subsequent data. If the response status code is either 200 OK or 304 Not Modified, it signifies that the current request has been successfully processed. client server
代码示例
// 长轮询实现
class LongPolling {
constructor(url, timeout = 30000) {
this.url = url
this.timeout = timeout
this.isRunning = false
}
async start() {
this.isRunning = true
while (this.isRunning) {
try {
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), this.timeout)
const response = await fetch(this.url, {
signal: controller.signal,
headers: {
'Cache-Control': 'no-cache',
'X-Requested-With': 'XMLHttpRequest'
}
})
clearTimeout(timeoutId)
if (response.ok) {
const data = await response.json()
console.log('**长轮询收到数据:**', data)
this.onData(data)
}
// **立即发起下一次请求**
await new Promise(resolve => setTimeout(resolve, 100)) // 短暂间隔防止过载
} catch (error) {
if (error.name === 'AbortError') {
console.log('长轮询超时,重新连接...')
} else {
console.error('长轮询错误:', error)
await new Promise(resolve => setTimeout(resolve, 5000)) // 错误重试间隔
}
}
}
}
stop() {
this.isRunning = false
}
onData(data) {
// 处理数据回调
}
}
// 服务端实现 (Node.js + Express)
app.get('/api/longpoll', (req, res) => {
const timeout = 30000 // 30秒超时
// **检查是否有立即可用的数据**
const immediateData = checkForUpdates()
if (immediateData) {
return res.json(immediateData)
}
// 设置超时
const timer = setTimeout(() => {
res.status(304).send() // No Modified
}, timeout)
// **监听数据更新事件**
const onUpdate = (data) => {
clearTimeout(timer)
res.json(data)
eventEmitter.off('dataUpdate', onUpdate)
}
eventEmitter.on('dataUpdate', onUpdate)
// 客户端断开连接时清理
req.on('close', () => {
clearTimeout(timer)
eventEmitter.off('dataUpdate', onUpdate)
})
})
javascript

优缺点 :
- ✅ 实时性得到显著提升 ,数据一旦送达立即完成推送
- ✅ 优化了请求频率 ,相较于短轮询方案更加高效
- ❌ 增加了系统负载 ,维持大量连接状态
- ❌ 超时情况处理较为繁琐
3. WebSocket - 专线电话 ☎️
比喻 :像拉了一根专线电话,双方随时可以通话,信息瞬间到达。
流程图
客户端与服务器之间的HTTP升级请求中包含了以下操作:通过WebSocket协议建立连接以实现 WebSocket 连接的创建;向 WebSocket 连接发送消息以实现实时数据推送;在检测到客户端的变化信息后向服务器发起 HTTP/101 备用协议请求;服务器接收到该请求后返回响应并同步双方的数据;最后检测到断开连接时会触发相关的断开处理流程。
通过 WebSocket 协议实现双向通信,并确保在主动关闭时断开连接。
代码示例
// **客户端 WebSocket 实现**
class DroneWebSocket {
constructor(url) {
this.url = url
this.ws = null
this.reconnectAttempts = 0
this.maxReconnectAttempts = 5
this.reconnectInterval = 3000
}
connect() {
try {
this.ws = new WebSocket(this.url)
this.ws.onopen = () => {
console.log('**🎉 WebSocket连接成功**')
this.reconnectAttempts = 0
this.onConnected()
}
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data)
console.log('**📨 收到实时数据:**', data)
this.handleMessage(data)
}
this.ws.onclose = (event) => {
console.log('**❌ WebSocket连接关闭**', event.code, event.reason)
this.handleReconnect()
}
this.ws.onerror = (error) => {
console.error('**🚨 WebSocket错误:**', error)
}
} catch (error) {
console.error('WebSocket连接失败:', error)
this.handleReconnect()
}
}
// **发送消息**
send(message) {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(message))
} else {
console.warn('WebSocket未连接,消息发送失败')
}
}
// **断线重连**
handleReconnect() {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++
console.log(`⏳ ${this.reconnectInterval/1000}秒后尝试第${this.reconnectAttempts}次重连...`)
setTimeout(() => {
this.connect()
}, this.reconnectInterval)
} else {
console.error('**❌ 重连失败,已达到最大重连次数**')
}
}
// **处理不同类型的消息**
handleMessage(data) {
switch (data.type) {
case 'drone_status':
this.updateDroneStatus(data.payload)
break
case 'flight_update':
this.updateFlightInfo(data.payload)
break
case 'alert':
this.showAlert(data.payload)
break
default:
console.log('未知消息类型:', data.type)
}
}
updateDroneStatus(droneData) {
// **实时更新无人机状态**
const droneElement = document.querySelector(`[data-drone-id="${droneData.id}"]`)
if (droneElement) {
droneElement.classList.toggle('online', droneData.status === 'online')
droneElement.classList.toggle('flying', droneData.status === 'flying')
}
}
close() {
if (this.ws) {
this.ws.close()
}
}
}
// **使用示例**
const droneSocket = new DroneWebSocket('ws://localhost:8080/drone-updates')
droneSocket.connect()
// 发送控制指令
droneSocket.send({
type: 'control',
action: 'takeoff',
droneId: 'drone-001'
})
// **服务端实现 (Node.js + ws)**
const WebSocket = require('ws')
const wss = new WebSocket.Server({ port: 8080 })
wss.on('connection', (ws) => {
console.log('**🎉 新客户端连接**')
// **发送欢迎消息**
ws.send(JSON.stringify({
type: 'welcome',
payload: { message: '连接成功,开始接收实时数据' }
}))
// **监听客户端消息**
ws.on('message', (message) => {
const data = JSON.parse(message)
console.log('收到客户端消息:', data)
// **处理控制指令**
if (data.type === 'control') {
handleDroneControl(data)
}
})
// **定时推送实时数据**
const interval = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({
type: 'drone_status',
payload: generateDroneStatusUpdate()
}))
}
}, 1000)
ws.on('close', () => {
console.log('**❌ 客户端断开连接**')
clearInterval(interval)
})
})
javascript

优缺点 :
- ✅ 完全实时 ,延迟极小
- ✅ 双向通信能力 ,服务器端具备主动推送功能
- ✅ 传输效率高 ,通信开销较低
- ❌ 计算复杂度较高 ,存在断线后重连处理需求
- ❌ 代理兼容性差 ,部分网络环境存在问题
4. Server-Sent Events (SSE) - 新闻推送 📺
比喻 :像安装了新闻客户端后,在电视台有新闻时会自动同步更新内容;但无法向电视台发送信息。
流程图
客户端服务器通过 GET 请求至 /api/events 路径,并接受 Accept 头部指定为 text/event-stream 格式的流式事件数据。状态码为 200 且保持 keep-alive 连接状态下, 系统会创建流式 Push 连接给客户端, 并持续发送数据包:包括更新型数据包、警报型数据包和状态型数据包. 在该过程中,默认情况下仅限接收而不支持发送; 循环中由服务器主动推送; 当连接存活时会持续提供更新; 当客户端断开时则会关闭该连接并停止提供数据.
代码示例
// **客户端 SSE 实现**
class DroneSSE {
constructor(url) {
this.url = url
this.eventSource = null
this.reconnectAttempts = 0
this.maxReconnectAttempts = 5
this.reconnectDelay = 3000
}
connect() {
try {
this.eventSource = new EventSource(this.url)
this.eventSource.onopen = () => {
console.log('**🎉 SSE连接成功**')
this.reconnectAttempts = 0
}
// **监听默认消息**
this.eventSource.onmessage = (event) => {
const data = JSON.parse(event.data)
console.log('**📡 收到SSE数据:**', data)
this.handleData(data)
}
// **监听自定义事件类型**
this.eventSource.addEventListener('drone-update', (event) => {
const droneData = JSON.parse(event.data)
this.updateDroneStatus(droneData)
})
this.eventSource.addEventListener('flight-alert', (event) => {
const alertData = JSON.parse(event.data)
this.showFlightAlert(alertData)
})
this.eventSource.addEventListener('system-status', (event) => {
const statusData = JSON.parse(event.data)
this.updateSystemStatus(statusData)
})
this.eventSource.onerror = (error) => {
console.error('**🚨 SSE连接错误:**', error)
if (this.eventSource.readyState === EventSource.CLOSED) {
console.log('**❌ SSE连接已关闭,尝试重连...**')
this.handleReconnect()
}
}
} catch (error) {
console.error('SSE连接失败:', error)
this.handleReconnect()
}
}
handleReconnect() {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++
console.log(`⏳ ${this.reconnectDelay/1000}秒后尝试第${this.reconnectAttempts}次重连...`)
setTimeout(() => {
this.connect()
}, this.reconnectDelay)
} else {
console.error('**❌ SSE重连失败,已达到最大重连次数**')
}
}
handleData(data) {
switch (data.type) {
case 'drone_count':
this.updateDroneCount(data.payload)
break
case 'real_time_position':
this.updateDronePosition(data.payload)
break
default:
console.log('未知数据类型:', data.type)
}
}
updateDroneCount(countData) {
// **实时更新无人机统计数据**
document.querySelector('#online-count').textContent = countData.online
document.querySelector('#flying-count').textContent = countData.flying
document.querySelector('#offline-count').textContent = countData.offline
}
updateDronePosition(positionData) {
// **实时更新无人机位置**
const { droneId, lat, lng, altitude } = positionData
MapService.updateDronePosition(lng, lat, altitude, 'flying', droneId)
}
close() {
if (this.eventSource) {
this.eventSource.close()
}
}
}
// **服务端实现 (Node.js + Express)**
app.get('/api/drone-events', (req, res) => {
// **设置SSE响应头**
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Cache-Control'
})
console.log('**🎉 新的SSE客户端连接**')
// **发送连接确认**
res.write('data: {"type":"connected","message":"SSE连接成功"}\n\n')
// **定时发送无人机统计数据**
const statsInterval = setInterval(() => {
const stats = getDroneStats()
res.write(`event: drone-update\n`)
res.write(`data: ${JSON.stringify(stats)}\n\n`)
}, 5000)
// **实时位置更新**
const positionInterval = setInterval(() => {
const positions = getAllDronePositions()
positions.forEach(pos => {
res.write(`event: position-update\n`)
res.write(`data: ${JSON.stringify(pos)}\n\n`)
})
}, 1000)
// **系统状态推送**
const statusInterval = setInterval(() => {
const systemStatus = getSystemStatus()
res.write(`event: system-status\n`)
res.write(`data: ${JSON.stringify(systemStatus)}\n\n`)
}, 10000)
// **客户端断开连接时清理**
req.on('close', () => {
console.log('**❌ SSE客户端断开连接**')
clearInterval(statsInterval)
clearInterval(positionInterval)
clearInterval(statusInterval)
})
req.on('error', (err) => {
console.error('SSE连接错误:', err)
})
})
// **使用示例**
const droneSSE = new DroneSSE('/api/drone-events')
droneSSE.connect()
javascript

优缺点 :
- ✅ 简洁明了地遵循HTTP规范
- ✅ 简单直观的功能由内置机制保障
- ✅ 明确分类有助于识别内容类型
- ❌ 单一方向的信息传递导致交流受限
- ❌ 访问数量受限同一网站内访问受限
🎯 技术选择指南
| 场景 | 推荐技术 | 原因 |
|---|---|---|
| 简单状态查询 | 短轮询 | 实现简单,服务器压力小 |
| 实时性要求不高 | 长轮询 | 平衡实时性和资源消耗 |
| 高实时性 + 双向通信 | WebSocket | 游戏、聊天、协作编辑 |
| 单向推送 + 简单 | SSE | 通知、状态更新、股价推送 |
🚁 在无人机项目中的应用建议
// **混合方案示例**
class UAVCommunicationManager {
constructor() {
// **WebSocket用于控制指令**
this.controlSocket = new DroneWebSocket('ws://api/control')
// **SSE用于状态推送**
this.statusSSE = new DroneSSE('/api/status-stream')
// **短轮询用于非关键数据**
this.statisticsPoller = new ShortPolling('/api/statistics', 30000)
}
start() {
this.controlSocket.connect() // **实时控制**
this.statusSSE.connect() // **状态推送**
this.statisticsPoller.start() // **统计数据**
}
}
javascript

核心要点 :
网络通信协议用于实现实时控制指令及紧急情况的处理流程。状态更新服务负责传输无人机当前位置及相关动态信息。定期查询机制收集并存储包括统计数据和历史记录在内的非实时更新数据。
这样的组合能够在保证实时性的同时,最大化系统的稳定性和可维护性!🎉
