【问题标题】:Use express as proxy for websocket使用 express 作为 websocket 的代理
【发布时间】:2021-07-21 21:25:31
【问题描述】:

我有一个数据提供者,它通过 TCP 连接为我提供股票价格。数据提供者只允许静态 IP 连接到他们的服务。

但由于我需要在将数据发送到前端之前对其进行格式化,因此我想使用我的 express 后端作为代理。

这意味着:

  • 我需要通过 websocket(socket.io) 将我的后端连接到我的数据提供者以获取数据(后端充当客户端)
  • 我需要我的后端将收到的数据广播到我的前端(后端充当服务器)

我的问题是:这可能吗?有没有更简单的方法来实现这一目标?是否有关于如何将 express 应用程序同时用作 websocket 服务器和客户端的文档?


编辑:

我现在开始工作了。但是我当前的解决方案由于 CPU 使用量巨大而杀死了我的 AWS EC2 实例。这就是我实现它的方式:

const net = require('net');
const app = require('express')();
const httpServer = require('http').createServer(app);

const client = new net.Socket();

const options = {
  cors: {
    origin: 'http://someorigin.org',
  },
};

const io = require('socket.io')(httpServer, options);

client.connect(1337, 'some.ip', () => {
  console.info('Connected to some.ip');
});

client.on('data', async (data) => {
  // parse data
  const parsedData = {
    identifier: data.identifier,
    someData: data.someData,
  };

  // broadcast data
  io.emit('randomEmitString', parsedData);
});

client.on('close', () => {
  console.info('Connection closed');
});

httpServer.listen(8081);

有谁知道为什么这会导致巨大的 CPU 负载?我尝试使用 clinicjs 分析我的代码,但找不到明显的问题。


EDIT2:更具体地说:我的数据提供商为我提供股票报价。所以每次报价发生变化时,我都会得到新的数据。然后我解析这些数据并通过io.emit 发出它。这会是某种瓶颈吗?

这是我运行clinicjs后得到的配置文件:

【问题讨论】:

  • 当然。您可以使用io.emit() 向 Socket.io 中所有连接的客户端广播消息(其中ioinitialized Socket.io server instance)。 Socket.io服务器启动后连接数据提供者即可。
  • 您确定要与数据提供者建立(低级)套接字连接,而不是 socket.io 套接字、ws 套接字或 http 连接吗?
  • 注意:socket.io 不是普通的 websocket 客户端/服务器。
  • afaik 我的数据提供者只允许 TCP 连接。我用新信息再次更新了我的问题
  • @Ic3m4n,您运行 Clinicjs 时的客户端(前端客户端)连接数是多少?

标签: javascript node.js express websocket


【解决方案1】:

我不知道您的 AWS 上有多少资源,但 1,000 个客户端应该不是问题。

我个人遇到过2个瓶颈:

  1. 使用 Ajax 连接的客户端,而不是 WS(这曾经是旧 socket.io 的常见问题)
  2. socket.io 库由 Node 提供,而不是 Nginx / Apache。节点在保持活动管理方面很差。

也检查一下:

  1. 您多久从some.ip 获取数据?好主意是聚合并过滤它。
  2. 您需要通知所有客户吗?只是通知感兴趣就足够了吗? (直播区)
  3. 也许值得将服务移至 serviceWorker.js 或推送事件?

作为实验的一部分,记录自己的事件。接收数据,连接和断开客户端。观察服务器日志。

作为调试过程的一部分,记录事件。接收数据,连接和断开客户端。 观察服务器日志。

或者也许这段代码不对问题负责,而是第一次查看的数据下载。缓冲区中有数据,还是读取GET index.html

【讨论】:

    【解决方案2】:

    为了了解您的情况,我创建了一个基本的 TCP 服务器,它每 1 毫秒向连接到它的每个客户端发布 JSON 消息。这是服务器的代码:

    var net = require('net');
    
    var server = net.createServer(function(socket) {
        socket.pipe(socket);
    });
    
    server.maxConnections = 10
    
    server.on('close', ()     => console.log('server closed'))
    server.on('error', (err)  => console.error(err))
    server.on('listening', () => console.log('server is listening'))
    server.on('connection', (socket) => {
      console.log('- client connected')
      socket.setEncoding('utf8')
    
      var intervalId = setInterval(() => socket.readyState === "open" && 
        socket.write(JSON.stringify({
          id: intervalId,
          timestamp: Date.now(),
        }) + '\n'), 1)
    
      socket.on('error'  , (err) => console.error(err))
      socket.on('close'  , ()    => {
        clearInterval(intervalId)
        console.log('- client closed the connection')
      })
    })
    
    server.listen(1337, '0.0.0.0');
    

    如您所见,我们设置了一个 setInterval 函数,它将每 1 毫秒向每个连接的客户端发送一条简单的 JSON 消息。

    对于客户,我使用了与您所拥有的非常相似的东西。起初,我尝试将服务器接收到的每条消息推送到浏览器到 WebSocket 连接。就我而言,它还将 CPU 推到了 100%。我不知道具体为什么。

    尽管如此,即使您的数据每 1 毫秒更新一次,您是否需要以该速率刷新网页也是值得怀疑的。大多数网站以 60 fps 的速度运行。这意味着每 16 毫秒更新一次数据。因此,一个简单的解决方案是批量处理数据并每 16 毫秒将其发送到浏览器。只是这个修改大大提高了性能。您可以通过延长批处理时间或过滤一些发送的数据来更进一步。

    这是客户端的代码,利用了批处理消息。请记住,这是一个非常幼稚的实现来展示这个想法。更好的调整是使用 RxJS 之类的库来处理流。

    // tcp-client.js
    const express    = require('express');
    const http       = require('http');
    const { Server } = require("socket.io");
    const net        = require('net')
    
    const app    = express();
    const server = http.createServer(app);
    const io     = new Server(server);
    const client = new net.Socket()
    
    app.get('/', (req, res) => {
      res.setHeader('content-type', 'text/html')
      res.send(`
    <!doctype html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <title>TCP - Client</title>
    </head>
    <body>
      <script src="/socket.io/socket.io.js"></script>
      <script>
        var socket = io();
        socket.on('msg', (msg) => document.body.textContent = msg);
      </script>
    </body>
    </html>
    `);
    });
    
    io.on('connection', (socket) => {
      console.log('- user connected');
      socket.on('disconnect', () => {
        console.log('- user disconnected');
      });
    });
    
    var buffer = []
    
    setInterval(() => {
      io.emit("msg", JSON.stringify(buffer))
      buffer = []
    }, 16)
    
    client.connect(1337, '127.0.0.1', function() {
        console.log('- connected to server');
    });
    
    client.on('data', function(data) {
      buffer.push(data.toString("utf8"))
    });
    
    client.on('close', function() {
        console.log('- connection to server closed');
    });
    
    server.listen(3000, () => {
      console.log('listening on 0.0.0.0:3000');
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-01
      • 1970-01-01
      • 2017-06-15
      • 1970-01-01
      • 1970-01-01
      • 2015-05-07
      • 1970-01-01
      • 2015-04-01
      相关资源
      最近更新 更多