当前位置: 首页 > news >正文

使用 WebSocket 实现手机控制端和电脑展示端的实时通信,包含断线重连功能。

主要分为三个部分:WebSocket 服务器、电脑展示端页面和手机控制端页面。        

1. WebSocket 服务器(Node.js)

首先需要搭建一个 WebSocket 服务器作为中间层,转发控制指令:

// server.js
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });// 存储连接的客户端,区分控制端和展示端
let controller = null;  // 手机控制端
let display = null;    // 电脑展示端console.log('WebSocket服务器启动,端口: 8080');wss.on('connection', (ws) => {console.log('新客户端连接');// 接收客户端消息ws.on('message', (message) => {try {const data = JSON.parse(message.toString());// 客户端类型注册if (data.type === 'register') {if (data.role === 'controller') {controller = ws;console.log('手机控制端已连接');// 通知控制端是否已有展示端连接ws.send(JSON.stringify({type: 'status',hasDisplay: !!display}));} else if (data.role === 'display') {display = ws;console.log('电脑展示端已连接');// 通知展示端是否已有控制端连接ws.send(JSON.stringify({type: 'status',hasController: !!controller}));}} // 转发控制指令else if (data.type === 'control' && controller === ws && display) {console.log('转发控制指令:', data);display.send(JSON.stringify(data));}} catch (e) {console.error('消息处理错误:', e);}});// 客户端断开连接ws.on('close', () => {if (ws === controller) {controller = null;console.log('手机控制端已断开');// 通知展示端控制端已断开if (display) {display.send(JSON.stringify({type: 'status',hasController: false}));}} else if (ws === display) {display = null;console.log('电脑展示端已断开');// 通知控制端展示端已断开if (controller) {controller.send(JSON.stringify({type: 'status',hasDisplay: false}));}}});// 错误处理ws.on('error', (error) => {console.error('WebSocket错误:', error);});
});
2. 电脑展示端页面(display.html)
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>电脑展示端</title><style>body {font-family: Arial, sans-serif;display: flex;flex-direction: column;align-items: center;justify-content: center;height: 100vh;margin: 0;transition: background-color 0.5s;}#status {position: fixed;top: 20px;padding: 10px 20px;border-radius: 5px;background-color: #f0f0f0;}.connected {background-color: #4CAF50;color: white;}.disconnected {background-color: #f44336;color: white;}#displayArea {width: 80%;height: 60%;border: 2px solid #333;border-radius: 10px;display: flex;align-items: center;justify-content: center;font-size: 24px;transition: all 0.3s;}</style>
</head>
<body><div id="status" class="disconnected">未连接到控制端</div><div id="displayArea">等待控制指令...</div><script>let ws;let reconnectInterval;const reconnectDelay = 3000; // 重连间隔3秒// 连接WebSocket服务器function connect() {// 关闭可能存在的旧连接if (ws) {ws.close();}// 获取当前页面的主机地址,确保使用相同的IPconst host = window.location.hostname;ws = new WebSocket(`ws://${host}:8080`);// 连接成功ws.onopen = () => {console.log('WebSocket连接成功');// 注册为展示端ws.send(JSON.stringify({type: 'register',role: 'display'}));// 清除重连计时器clearInterval(reconnectInterval);updateStatus(true);};// 接收消息ws.onmessage = (event) => {const data = JSON.parse(event.data);console.log('收到消息:', data);// 处理状态更新if (data.type === 'status') {updateStatus(data.hasController);}// 处理控制指令else if (data.type === 'control') {handleControl(data.command, data.value);}};// 连接关闭ws.onclose = () => {console.log('WebSocket连接关闭');updateStatus(false);// 启动重连机制startReconnect();};// 连接错误ws.onerror = (error) => {console.error('WebSocket错误:', error);updateStatus(false);};}// 启动重连机制function startReconnect() {console.log(`将在${reconnectDelay/1000}秒后尝试重连...`);reconnectInterval = setInterval(connect, reconnectDelay);}// 更新连接状态显示function updateStatus(connected) {const statusEl = document.getElementById('status');if (connected) {statusEl.textContent = '已连接到控制端';statusEl.className = 'connected';} else {statusEl.textContent = '未连接到控制端,正在尝试重连...';statusEl.className = 'disconnected';}}// 处理控制指令function handleControl(command, value) {const displayArea = document.getElementById('displayArea');switch(command) {case 'changeColor':document.body.style.backgroundColor = value;displayArea.textContent = `背景色已更改为: ${value}`;break;case 'changeText':displayArea.textContent = value;break;case 'scale':displayArea.style.transform = `scale(${value})`;displayArea.textContent = `缩放比例: ${value}`;break;case 'rotate':displayArea.style.transform = `rotate(${value}deg)`;displayArea.textContent = `旋转角度: ${value}°`;break;default:console.log('未知指令:', command);}}// 初始化连接connect();</script>
</body>
</html>

3. 手机控制端页面(controller.html)
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"><title>手机控制端</title><style>body {font-family: Arial, sans-serif;padding: 20px;margin: 0;background-color: #f5f5f5;}#status {padding: 10px;border-radius: 5px;text-align: center;margin-bottom: 20px;}.connected {background-color: #4CAF50;color: white;}.disconnected {background-color: #f44336;color: white;}.control-group {background-color: white;padding: 15px;border-radius: 10px;margin-bottom: 15px;box-shadow: 0 2px 5px rgba(0,0,0,0.1);}h3 {margin-top: 0;color: #333;}button {width: 100%;padding: 12px;margin-bottom: 10px;border: none;border-radius: 5px;background-color: #2196F3;color: white;font-size: 16px;cursor: pointer;}button:hover {background-color: #0b7dda;}input[type="color"], input[type="text"] {width: 100%;padding: 10px;margin-bottom: 10px;border: 1px solid #ddd;border-radius: 5px;box-sizing: border-box;}input[type="range"] {width: 100%;margin: 15px 0;}.range-value {text-align: center;font-weight: bold;}</style>
</head>
<body><div id="status" class="disconnected">未连接到展示端</div><div class="control-group"><h3>背景颜色控制</h3><input type="color" id="bgColor" value="#ffffff"><button onclick="sendCommand('changeColor', document.getElementById('bgColor').value)">更改背景色</button></div><div class="control-group"><h3>文本控制</h3><input type="text" id="displayText" placeholder="输入要显示的文本"><button onclick="sendCommand('changeText', document.getElementById('displayText').value)">更新显示文本</button></div><div class="control-group"><h3>缩放控制</h3><input type="range" id="scale" min="0.5" max="2" step="0.1" value="1"><div class="range-value" id="scaleValue">1.0</div><button onclick="sendCommand('scale', document.getElementById('scale').value)">应用缩放</button></div><div class="control-group"><h3>旋转控制</h3><input type="range" id="rotate" min="0" max="360" step="15" value="0"><div class="range-value" id="rotateValue">0°</div><button onclick="sendCommand('rotate', document.getElementById('rotate').value)">应用旋转</button></div><script>let ws;let reconnectInterval;const reconnectDelay = 3000; // 重连间隔3秒let isConnected = false;// 更新滑块显示值document.getElementById('scale').addEventListener('input', function() {document.getElementById('scaleValue').textContent = this.value;});document.getElementById('rotate').addEventListener('input', function() {document.getElementById('rotateValue').textContent = this.value + '°';});// 连接WebSocket服务器function connect() {// 关闭可能存在的旧连接if (ws) {ws.close();}// 获取当前页面的主机地址,确保使用相同的IPconst host = window.location.hostname;ws = new WebSocket(`ws://${host}:8080`);// 连接成功ws.onopen = () => {console.log('WebSocket连接成功');// 注册为控制端ws.send(JSON.stringify({type: 'register',role: 'controller'}));// 清除重连计时器clearInterval(reconnectInterval);};// 接收消息ws.onmessage = (event) => {const data = JSON.parse(event.data);console.log('收到消息:', data);// 处理状态更新if (data.type === 'status') {isConnected = data.hasDisplay;updateStatus(isConnected);}};// 连接关闭ws.onclose = () => {console.log('WebSocket连接关闭');isConnected = false;updateStatus(false);// 启动重连机制startReconnect();};// 连接错误ws.onerror = (error) => {console.error('WebSocket错误:', error);isConnected = false;updateStatus(false);};}// 启动重连机制function startReconnect() {console.log(`将在${reconnectDelay/1000}秒后尝试重连...`);reconnectInterval = setInterval(connect, reconnectDelay);}// 更新连接状态显示function updateStatus(connected) {const statusEl = document.getElementById('status');if (connected) {statusEl.textContent = '已连接到展示端';statusEl.className = 'connected';} else {statusEl.textContent = '未连接到展示端,正在尝试重连...';statusEl.className = 'disconnected';}}// 发送控制指令function sendCommand(command, value) {if (!isConnected || !ws) {alert('未连接到展示端,请稍后重试');return;}try {ws.send(JSON.stringify({type: 'control',command: command,value: value}));console.log(`发送指令: ${command} = ${value}`);} catch (e) {console.error('发送指令失败:', e);alert('发送指令失败,请重试');}}// 初始化连接connect();</script>
</body>
</html>

使用说明

  1. 环境准备

    • 安装 Node.js
    • 安装 WebSocket 模块:npm install ws
  2. 启动服务器

    • 运行命令:node server.js
    • 服务器将在 8080 端口启动
  3. 部署页面

    • 将 display.html 和 controller.html 放在 Web 服务器(如 Nginx、Apache)或使用简单的 HTTP 服务器
    • 例如:使用 Node.js 的 http-server:npx http-server
  4. 使用方法

    • 确保手机和电脑连接到同一网络
    • 在电脑上打开展示端页面:http://[服务器IP]:8080/display.html
    • 在手机上打开控制端页面:http://[服务器IP]:8080/controller.html
    • 现在可以通过手机控制电脑页面的各种属性了

断线重连机制说明

  • 当连接断开时,客户端会自动尝试重连
  • 重连间隔为 3 秒,可通过修改reconnectDelay变量调整
  • 重连过程中会显示状态提示
  • 重连成功后会自动恢复通信,无需手动操作

这个实现提供了基本的控制功能(颜色、文本、缩放、旋转),你可以根据需要扩展更多控制指令和 UI 元素。

http://www.dtcms.com/a/523776.html

相关文章:

  • 服装网站建设怎么写wordpress strip_tags
  • 一文讲清:数据清洗、数据中台、数据仓库、数据治理
  • 【C++ STL】探索STL的奥秘——vector底层的深度剖析和模拟实现!
  • STM32CUBEMX安装离线库
  • 体验 Suno v5:最新的 Suno AI 音乐模型
  • 2.4 欧拉集群安装Nova计算服务
  • 贵港网站建设兼职免费广告设计网站
  • Cell Mol Biol Lett|Runx2诱导超级沉默子形成下调Lpl表达:重塑雪旺细胞脂质代谢的新机制
  • 国自然·医工交叉热点|泛癌组织学重建AI模型
  • Python依赖管理与环境迁移实战:Poetry+Docker构建高效开发体系
  • 山西网站建设推荐景区网站如何建设
  • Flutter---CupertinoPicker滚动选择器
  • 全面掌握PostgreSQL关系型数据库,备份和恢复,笔记46和笔记47
  • Python SQLAlchemy模块:从入门到实战的数据库操作指南
  • 天津哪里有做网站的jquery wordpress
  • 流媒体网站建设规划亚马逊网站建设案例
  • PHP 异步IO扩展包 AsyncIO v2.0.0 发布
  • 《信息系统项目管理师》案例分析题及解析模拟题5
  • Jenkins上实现CI集成软件信息Teams群通知案例实现。
  • ZYNQ平台中断服务函数中的变量不加volatile修饰导致的奇怪问题解决
  • 2026年UX/UI五大趋势:AI、AR与包容性设计将重新定义用户体验
  • 网站做跳转自己建网站卖鞋
  • 百度网站服务器外贸网站优化
  • 应广单片机烧录跳线J7专用PCB使用说明
  • Java 前后端加密与编码技术:从概念到实战场景全解析
  • 拒绝笨重,一款轻量、极致简洁的开源接口管理工具 - PostIn
  • 建设银行信用卡网站是哪个茶叶seo网站推广与优化方案
  • vant van-uploader上传file文件;回显时使用imageId拼接路径
  • Java常用中间件整理讲解——Redis,RabbitMQ
  • JavaEE初阶7.0