原生websocket 双工demo

Server.mjs

javascript 复制代码
import { createServer } from 'node:http';
import { readFile } from 'node:fs/promises';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';

import { WebSocketServer } from 'ws';

const HERE = dirname(fileURLToPath(import.meta.url));
const sockets = new Set();

const server = createServer(async (req, res) => {
  const url = new URL(req.url ?? '/', `http://127.0.0.1:8788`);

  if (req.method === 'GET' && (url.pathname === '/' || url.pathname === '/index.html')) {
    const html = await readFile(join(HERE, 'test.html'), 'utf8');
    res.writeHead(200, { 'content-type': 'text/html; charset=utf-8' });
    res.end(html);
    return;
  }
});

const wss = new WebSocketServer({ server, path: '/ws' });

wss.on('connection', (socket) => {
  sockets.add(socket);
  console.log(`[ws] client connected (${sockets.size})`);

  // 立即推送一条消息
  socket.send(JSON.stringify({ type: 'welcome', message: '欢迎连接!' }));

  // 收到消息
  socket.on('message', (data) => {
    const message = data.toString();
    console.log('收到客户端消息:', message);
    try {
      const parsed = JSON.parse(message);
      console.log('解析后:', parsed);
      // 回复客户端
      socket.send(
        JSON.stringify({
          type: 'response',
          message: `收到你的消息: ${parsed.input || parsed.message || '未知'}`,
          timestamp: new Date().toLocaleTimeString(),
        })
      );
    } catch (e) {
      console.log('非 JSON 数据:', message);
      socket.send(JSON.stringify({ type: 'echo', message: message }));
    }
  });

  socket.on('close', () => {
    sockets.delete(socket);
    console.log(`[ws] client disconnected (${sockets.size})`);
  });
});

server.listen('8788', '127.0.0.1', () => {
  console.log(`demo ready: http://127.0.0.1:8788`);
  //   console.log(`ws endpoint: ws://127.0.0.1:8788/ws  (event: message.stream)`);
});

client.mjs

javascript 复制代码
import WebSocket from 'ws';
const ws = new WebSocket('ws://127.0.0.1:8788/ws');

// 连接成功
ws.on('open', () => {
  console.log('已连接');
  ws.send(JSON.stringify({ input: 'hello' }));
});

// 收到消息
ws.on('message', (data) => {
  const message = data.toString();
  console.log('收到服务器消息:', message);
  try {
    const parsed = JSON.parse(message);
    console.log('解析后:', parsed);
    // 只在收到 welcome 时回复一次
    if (parsed.type === 'welcome') {
      ws.send(JSON.stringify({ type: 'hello', message: '你好服务器!' }));
    }
  } catch (e) {
    console.log('非 JSON 数据:', message);
  }
});

// 连接关闭
ws.on('close', () => {
  console.log('连接断开');
});

// 连接错误
ws.on('error', (error) => {
  console.error('连接错误:', error);
});

index.html

html 复制代码
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    test
  </body>
</html>
相关推荐
limit00752 小时前
三维 WebGIS 工具选型:加载、样式、分析、交付,一套界面能做完什么
android·前端·web3·安卓·webgl
全栈项目管理程序猿2 小时前
ArcGIS JS 基础教程(35):体元系列 - VoxelLayer 时间维度动画
前端·javascript
mantou1322 小时前
从纯 CSR 到 SSR:用 WebComponents 做一个 Next.js 式框架 Gemkit
前端·全栈·web components
cidy_982 小时前
深度拆解任务工作台架构:左右分栏、队列管理、实时刷新全方案
前端
Linye2 小时前
告别“PRD 与原型两张皮”!我们把可交互原生组件直接嵌进了需求文档,还能双向回写 Markdown
前端
deli0072 小时前
RSA 为什么公开公钥也解不开?2 个质数拆开实测一遍
前端
ModyQyW2 小时前
vite-plugin-uni-pages 0.6:统一扫描规则,开发期少重启
前端·uni-app
门思科技2 小时前
把 ThinkLink 接进 Home Assistant 与 Node-RED:一条 MQTT 转发器能走通的路
前端
没事写点啥2 小时前
WeKnora 回答溯源
前端·后端·ai编程