You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用NodeJS搭建适配Python异步WebSocket握手的服务器?

实现对接Python WebSocket客户端的Node.js服务器

不用慌,处理这种有序双向消息其实很简单——因为WebSocket基于TCP协议,消息本身就是按顺序传输的,我们只要在服务器端按照客户端发送消息的顺序依次接收、处理、响应就可以了。我推荐用ws这个最流行的Node.js WebSocket库来实现,下面直接给你完整的可运行代码,再拆解关键逻辑。

第一步:安装依赖

先安装ws库:

npm install ws

第二步:完整服务器代码

const WebSocket = require('ws');
const crypto = require('crypto');

// 必须和Python客户端保持一致的DH参数(g、N)
const g = 2;
const N = BigInt('ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff');

// 创建WebSocket服务器,监听3000端口
const wss = new WebSocket.Server({ port: 3000 });

wss.on('connection', async (ws) => {
  console.log('新客户端连接');

  try {
    // 1. 接收客户端发送的邮箱
    const email = await waitForMessage(ws);
    console.log(`收到邮箱: ${email}`);

    // 2. 生成32字节随机数r,转十六进制发送给客户端
    const r = crypto.randomBytes(32);
    ws.send(r.toString('hex'));

    // 3. 接收客户端发送的A(十六进制字符串),转成BigInt
    const AHex = await waitForMessage(ws);
    const A = BigInt(`0x${AHex}`);
    console.log(`收到A: ${AHex}`);

    // 4. 生成服务器端的b和B,将B转十六进制发送给客户端
    const bBytes = crypto.randomBytes(32);
    const b = BigInt(`0x${bBytes.toString('hex')}`);
    const B = (BigInt(g) ** b) % N;
    ws.send(B.toString(16));
    console.log(`发送B: ${B.toString(16)}`);

    // 5. 计算u、x、S(注意:实际应用中要从数据库取用户密码,这里为示例硬编码)
    const userPassword = 'user123'; // 替换为实际用户的密码
    // 计算sha256(email:pw)
    const emailPwHash = crypto.createHash('sha256')
      .update(Buffer.from(`${email}:${userPassword}`))
      .digest();
    // 计算x = sha256(r + sha256(email:pw))
    const xHash = crypto.createHash('sha256')
      .update(Buffer.concat([r, emailPwHash]))
      .digest();
    const x = BigInt(`0x${xHash.toString('hex')}`);

    // 计算u = sha256(A字节 + B字节)
    const ABuf = hexToBigIntBuffer(A);
    const BBuf = hexToBigIntBuffer(B);
    const uHash = crypto.createHash('sha256')
      .update(Buffer.concat([ABuf, BBuf]))
      .digest();
    const u = BigInt(`0x${uHash.toString('hex')}`);

    // 计算S = (B - g^x mod N)^(b + u*x) mod N
    const gxModN = (BigInt(g) ** x) % N;
    const base = (B - gxModN + N) % N; // 加N防止负数
    const exponent = (b + u * x) % N;
    const S = (base ** exponent) % N;
    console.log(`计算得到S: ${S.toString(16)}`);

    // 6. 接收客户端发送的token,验证是否匹配H(A||B||S)
    const clientToken = await waitForMessage(ws);
    const SBuf = hexToBigIntBuffer(S);
    const expectedToken = crypto.createHash('sha256')
      .update(Buffer.concat([ABuf, BBuf, SBuf]))
      .digest('hex');

    let result;
    if (clientToken === expectedToken) {
      result = 'success';
      console.log('Token验证通过,握手成功');
    } else {
      result = 'failure';
      console.log('Token验证失败');
    }

    // 7. 发送验证结果给客户端
    ws.send(result);

  } catch (err) {
    console.error('握手过程出错:', err);
    ws.send('error');
    ws.close();
  }
});

// 封装一个等待单条消息的工具函数,简化代码
function waitForMessage(ws) {
  return new Promise((resolve) => {
    ws.once('message', (data) => resolve(data.toString()));
  });
}

// 把BigInt转成固定64字节的Buffer(和Python的int2bytes对齐)
function hexToBigIntBuffer(num) {
  const hexStr = num.toString(16).padStart(64, '0');
  return Buffer.from(hexStr, 'hex');
}

console.log('WebSocket服务器运行在 ws://localhost:3000');

关键逻辑说明

1. 有序消息处理的核心

我封装了waitForMessage函数,用await依次等待每一条消息——这样就严格遵循了客户端的发送顺序:只有前一条消息处理完,才会等待下一条。加上WebSocket本身的TCP有序传输特性,完全不用担心消息乱序的问题。

2. 与Python客户端的参数对齐

  • 确保g和N这两个DH参数和Python客户端完全一致,否则密钥计算会彻底出错。
  • 字节与十六进制的转换要和客户端对齐:比如Python里用unhexlify接收r,所以服务器要发送十六进制字符串;Python用int(await websocket.recv(),16)接收B,服务器就发送B的十六进制字符串。
  • 用Node.js的BigInt处理大整数,避免普通Number的精度丢失问题。

3. 实际应用注意事项

  • 密码存储:示例里硬编码了密码,实际要从数据库取用户的密码(如果按照客户端的逻辑,需要存储原始密码,但这很不安全——建议修改客户端逻辑,改用加盐哈希存储,服务器存储盐和哈希值,这样更安全)。
  • 错误处理:代码里加了try-catch,避免单个连接的错误影响整个服务器。
  • 连接管理:可以根据需求添加连接断开、心跳检测等逻辑。

内容的提问来源于stack exchange,提问作者Pro7ech

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:45:48