Xterm.js: Control de flujo mediante XON / XOFF

Creado en 10 nov. 2020  ·  3Comentarios  ·  Fuente: xtermjs/xterm.js

Hola colaboradores,

Estoy usando xtermjs para crear una aplicación de terminal que se ejecuta en un navegador web y el servidor de destino usa Linux. Me di cuenta de que xtermjs v4.9.0 no responde a ^ C cuando se ejecuta el comando yes .
Luego hice una copia de seguridad a v4.0.2 y habilité la opción useFlowControl , funcionó.

El useFlowControl usando XON / XOFF se agregó desde v2.3.0 (PR # 447) pero se eliminó de v4.1.0 (PR # 2422).
No encuentro ninguna discusión sobre el motivo para eliminarlo. ¿Tiene la solución XON / XOFF algún problema?

Si no es así, ¿podemos tener un plan para traer de vuelta esta función a la biblioteca o debería implementarla en mi propia aplicación?

El control de flujo descrito en el documento (https://xtermjs.org/docs/guides/flowcontrol/) no ayuda mucho ya que uso websocket para conectarme al backend.

typquestion

Comentario más útil

Eliminamos XON / XOFF porque no funcionó de manera confiable en algunos escenarios. Desde el fondo de mi cabeza, recuerdo que tuvimos problemas con el shell ZSH, que usaba las secuencias XON / XOFF para algo diferente. Creo que la Terminal de Windows también tuvo problemas con estas secuencias.

De todos modos, la forma en que resolví esto (también usando WebSockets, en mi caso socket.io pero no importa) es establecer manualmente un mecanismo de control de flujo sobre el propio socket.

Entonces, cada vez que llegan datos al socket que deben escribirse en xterm.js, aumentamos un contador, y una vez que los datos se escribieron con éxito en xterm.js (lo que significa que xterm.js los procesó), disminuimos ese contador .

Si el contador excede un cierto umbral, enviamos un mensaje pause través de Websocket, que en el lado del servidor pausará el flujo de pty ( terminalStream.pause() ). Una vez que bajamos de ese umbral, enviamos un mensaje resume través de Websocket, que en el lado del servidor reanudará el flujo pty ( terminalStream.resume() ).

Tenga en cuenta que los métodos terminalStream.pause() y terminalStream.resume() son los métodos de Stream incorporados de node.js para manejar la contrapresión. node-pty y ssh2 soportan el manejo de la contrapresión a través de estos métodos.

// client
const MAX_PENDING_WRITES = 5;
let pendingWrites = 0;
let paused = false;
socket.on('data', (data) => {
  pendingWrites++;
  xterm.write(data, () => {
    pendingWrites--;
    if (pendingWrites > MAX_PENDING_WRITES && !paused) {
      paused = true;
      socket.emit('pause');
      return;
    }
    if (pendingWrites <= MAX_PENDING_WRITES && paused) {
      paused = false;
      socket.emit('resume');
      return;
    }
  });
});

// server
terminalStream.on('data', (data) => socket.emit('data', data);
socket.on('data', (data) => terminalStream.write(data));
socket.on('pause', () => terminalStream.pause();
socket.on('resume', () => terminalStream.resume();

Este mecanismo está funcionando bastante confiable hasta ahora. El comando yes ya no inundará la conexión. Todavía hay un retraso de aproximadamente 0,5 segundos entre CTRL+C y la terminación real del comando en escenarios de alto rendimiento, pero en mi opinión eso está bien.

Espero que ayude.

Todos 3 comentarios

Eliminamos XON / XOFF porque no funcionó de manera confiable en algunos escenarios. Desde el fondo de mi cabeza, recuerdo que tuvimos problemas con el shell ZSH, que usaba las secuencias XON / XOFF para algo diferente. Creo que la Terminal de Windows también tuvo problemas con estas secuencias.

De todos modos, la forma en que resolví esto (también usando WebSockets, en mi caso socket.io pero no importa) es establecer manualmente un mecanismo de control de flujo sobre el propio socket.

Entonces, cada vez que llegan datos al socket que deben escribirse en xterm.js, aumentamos un contador, y una vez que los datos se escribieron con éxito en xterm.js (lo que significa que xterm.js los procesó), disminuimos ese contador .

Si el contador excede un cierto umbral, enviamos un mensaje pause través de Websocket, que en el lado del servidor pausará el flujo de pty ( terminalStream.pause() ). Una vez que bajamos de ese umbral, enviamos un mensaje resume través de Websocket, que en el lado del servidor reanudará el flujo pty ( terminalStream.resume() ).

Tenga en cuenta que los métodos terminalStream.pause() y terminalStream.resume() son los métodos de Stream incorporados de node.js para manejar la contrapresión. node-pty y ssh2 soportan el manejo de la contrapresión a través de estos métodos.

// client
const MAX_PENDING_WRITES = 5;
let pendingWrites = 0;
let paused = false;
socket.on('data', (data) => {
  pendingWrites++;
  xterm.write(data, () => {
    pendingWrites--;
    if (pendingWrites > MAX_PENDING_WRITES && !paused) {
      paused = true;
      socket.emit('pause');
      return;
    }
    if (pendingWrites <= MAX_PENDING_WRITES && paused) {
      paused = false;
      socket.emit('resume');
      return;
    }
  });
});

// server
terminalStream.on('data', (data) => socket.emit('data', data);
socket.on('data', (data) => terminalStream.write(data));
socket.on('pause', () => terminalStream.pause();
socket.on('resume', () => terminalStream.resume();

Este mecanismo está funcionando bastante confiable hasta ahora. El comando yes ya no inundará la conexión. Todavía hay un retraso de aproximadamente 0,5 segundos entre CTRL+C y la terminación real del comando en escenarios de alto rendimiento, pero en mi opinión eso está bien.

Espero que ayude.

@tandatle Consulte también la documentación sobre flowcontrol .

Editar: Lo siento, pasé por alto su comentario de documentos. ¿Te importaría explicar lo que no está claro allí? Sí, la sección de websocket es solo un código auxiliar (no un fragmento listo para usar), ya que no hice qué crear toneladas de fragmentos para diferentes bibliotecas de sockets y necesidades personalizadas (esto es difícil de hacer bien con websockets solo por razones de seguridad) . Aún así, siéntase libre de agregar un fragmento concreto que cubra esos aspectos.

@mofux @jerch Gracias por su ayuda.
No estoy usando node.js en el backend, sino un proceso escrito en C ++, por lo que es posible que tenga que hacer algunas investigaciones más para elegir entre usar XON / XOFF e implementar el manejo de backpresure en mi proceso de backend.
Muchas gracias.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

albinekb picture albinekb  ·  4Comentarios

jerch picture jerch  ·  3Comentarios

LB-J picture LB-J  ·  3Comentarios

jestapinski picture jestapinski  ·  3Comentarios

travisobregon picture travisobregon  ·  3Comentarios