如何使用 socket.io 从 node.js 服务器在客户端(网络浏览器)显示实时数据?

How to use socket.io to display realtime data in the client (web browser) from the node.js server?

我想在浏览器中显示实时语音转文本数据。我所说的实时是指,“在我说话的同时,我正在同时获取文本输出”。我已经使用 Google 云服务 API 在 Python 中实现了语音转文本部分。然后我在 node.js 环境中对 运行 我的 python 程序使用“子进程”。到现在为止一切都很好。接下来,我想在浏览器中显示实时文本。换句话说,我想将 python 的实时文本输出(现在是 运行ning in node.js 使用子进程)发送到 Web 浏览器。我试图用 socket.io 做到这一点。这是我的服务器端 (node.js) 代码,其中还应用了 socket.io:

const express = require('express');
//const router = express.Router();
const {spawn} = require('child_process');
const path = require('path');
const app = express();
const http = require('http');
const server = http.createServer(app);
//const server = http.createServer(app); 
const { Server } = require("socket.io");
const io = new Server(server);

function runScript(){
  return spawn('python3', [
          "-u",
    path.join(__dirname, 'script.py')
  ]);
}

const subprocess = runScript()


// print output of the script

app.get('/', (req,res) => {

        res.sendFile(__dirname + '/index.html');
});

io.on('connection', (socket) => {

subprocess.stdout.on('data', (data) => {
  //console.log(`data:${data}`);
        socket.on('message', (data) => {
                socket.broadcast.emit('message', data);
        });
});
});

server.listen(3000, () => {
  console.log('listening on *:3000');
});

上面我是先用子进程调用node.js里的python程序然后用socket.broadcast.emit将 python 程序的文本输出发送到我的客户端。客户端代码如下所示:

<!DOCTYPE html>

<html>
        <head>
        <script src="/socket.io/socket.io.js"></script>
        <script>
                var socket = io();

        var messages = document.getElementById('messages'); 

        //const EventEmitter = require('events');
        //const emitter = new EventEmitter()
        //emitter.setMaxListeners(50)
        socket.on('messages', function(data) {
                
                 document.querySelector("#style1".innerHTML = `<p>${data1}</p>`
               
        });
        </script>
        </head>

        <body id="messages">
                <h1> This is crazy </h1>
                <div id="style1">
                </div> 

        </body>

</html>

以上,我想在

标签内显示python程序的实时文本输出。 问题是,我无法在网络浏览器中获取任何内容。 我的 objective 是,我想在网络浏览器中实时显示我所说的任何内容。

我对socket.io了解不多。其实我也是第一次使用这个技术。

您的 Node.js 服务器将充当套接字服务器。正如您的代码所示,它在一个端口上侦听套接字连接,并在连接时创建一个套接字,然后您也可以通过该套接字发送消息。从简单粗略的审查来看,服务器代码看起来还不错。

在您的网页上,您正在创建套接字并侦听消息。

但是网页上的套接字 运行 还没有连接到服务器,这就是为什么还没有任何工作的原因。

假设您在本地主机上执行此操作,只需将套接字服务器地址添加到它的构造函数中,然后监听连接。

const socket = io('ws://localhost:3000');

socket.on('connect', () => {
  // do any authentication or handshaking here.
  console.log('socket connected');
});

更高级的实现应该优雅地处理关闭套接字。

根据以下评论:

I added the lines you suggested above. Even now nothing is visible on the webpage but I am getting this warning: (node:14016) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 message listeners added. Use emitter.setMaxListeners() to increase limit

仔细查看您的服务器代码,我相信这是根本问题

subprocess.stdout.on('data', (data) => {
  //console.log(`data:${data}`);
        socket.on('message', (data) => {
                socket.broadcast.emit('message', data);
        });
});
});

每次您从 subprocess.stdout 接收数据时,您都在向您的套接字添加一个新的 onmessage 事件处理程序,因此一段时间后,您添加了太多的事件处理程序。

重写你的逻辑,这样你只添加 socket.on('message') 一次(通常在你创建套接字之后)。

还值得注意的是,在上面的代码中,没有使用来自 stdout 的 data,因为 data 变量正在由您的 onmessage 在较低的范围内重新定义功能。由于正在重新定义数据,Python 程序的输出将被忽略。

我想这就是你想要的:

//echo any message you receive from the socket back to the socket
socket.on('message', (data) => {
  socket.broadcast.emit('message', data);
});

//send data from std out to the socket.
subprocess.stdout.on('data', (data) => {
  //console.log(`data:${data}`);
   socket.broadcast.emit('message', data);      
});