Pregunta

Estoy escribiendo un servidor de socket y un cliente de juegos flash. El juego requiere comandos en tiempo real tales como movimiento y giro. Es importante que estos comandos sean enviados por el servidor al cliente tan pronto como sea posible, ya que de lo contrario, los demás clientes se desincronizarán mucho con el cliente que se mueve / gira.

Este es un ejemplo del problema causado por la aritmética de Nagle:

Nota : consulte la tabla de comandos a continuación si desea comprender qué significan estos comandos.

El primero es el barco que moví (avanzó + derecha, se recibió adelante pero no con derecho)

Los comandos de envío del cliente:

84796: Sending data: 2#4
84796: Sending data: 2#2
84904: Sending data: 2#3
84904: Sending data: 2#0
86187: Sending data: 2#4
86188: Sending data: 2#2
86374: Sending data: 2#3
86404: Sending data: 2#0

El cliente recibe comandos:

79244: Raw receive: 3#3#4$
79244: New command: 3#3#4
79398: Raw receive: 3#3#2$3#3#3$3#3#0$
79399: New command: 3#3#2
79399: New command: 3#3#3
79399: New command: 3#3#0
80635: Raw receive: 3#3#4$
80635: New command: 3#3#4
80908: Raw receive: 3#3#2$3#3#3$3#3#0$
80908: New command: 3#3#2
80908: New command: 3#3#3
80908: New command: 3#3#0

" momento " es un término extraño que no significa lo que estoy tratando de decir, pero aquí parece la cantidad de tiempo en milisegundos después del comando anterior

  1. avanzar enviar por el cliente A (momento: 0), recibido por el cliente B (momento: 0)

  2. gira a la derecha enviar por el cliente A (momento: 0), recibido por el cliente B (momento: 155)

  3. deja de moverte enviar por el cliente A (momento: 108), recibido por el cliente B (momento: 0)

  4. deja de girar enviar por el cliente A (momento: 0), recibido por el cliente B (momento: 0)

  5. avanzar enviar por el cliente A (momento: 1283), recibido por el cliente B (momento: 1236)

  6. gira a la derecha enviar por el cliente A (momento: 1), recibido por el cliente B (momento: 273)

  7. detener el movimiento enviar por el cliente A (momento: 186), recibido por el cliente B (momento: 0)

  8. deja de girar enviar por el cliente A (momento: 30), recibido por el cliente B (momento: 0)

Esta es la tabla de comandos correspondiente a los comandos:

Cliente- > Servidor

2# (movement info)
0) now not turning
1) now turning left
2) now turning right
3) now not moving
4) now moving forward

Servidor- > Cliente

3# (movement info)
[shipId]#
0) now not turning
1) now turning left
2) now turning right
3) now not moving
4) now moving forward

Entonces, lo que puedes ver es que los comandos están totalmente desincronizados debido a " Nagle " ;. Esto hace que otros clientes reciban el comando de detener el movimiento al mismo tiempo que el comando de inicio del movimiento, lo que hace que el jugador no se mueva en absoluto.

Es por esto que necesito que estos comandos se envíen en tiempo real, tan rápido como sea posible por el servidor TCP. Una solución fácil sería simplemente deshabilitar Nagle. Sin embargo, tengo googled (tenga en cuenta que su sugerencia sobre tcp el mensaje parcial se implementa en mi sistema, pero no tiene nada que ver con la sincronización) un poco y notó que la gente no recomienda deshabilitar a Nagle.

¿Es cierto que no debería deshabilitar el algoritmo de Nagle por esta causa y, en cambio, debería buscar otra solución? ¿Por qué (no)?

Gracias de antemano. - Tom

¿Fue útil?

Solución

Desea usar TCP_NODELAY para desactivar el algoritmo de fastidio para ese socket. Hay configuraciones en los sistemas operativos modernos para deshabilitarlo en todo el sistema, y ?? IS está mal visto, pero no hay razón para que no lo hagas con un socket que SABES que necesitas baja latencia .

setsockopt (TCP_NODELAY)

Otros consejos

Si necesita ser lo más rápido posible, debes usar UDP.

Sin embargo, tenga en cuenta que TCP proporciona garantía de entrega y orden mientras que UDP no proporciona ninguna.

Ese punto parece ser un punto críticamente en esta aplicación, por lo que tendría que colocar su propio mecanismo de orden de comandos de confirmación / reintento en la parte superior.

Si quieres mantenerte con TCP, TCP__NODELAY te ayudará. A medida que avanza su juego, puede terminar requiriendo un flujo de datos para el cual TCP será adecuado sin TCP_NODELAY.

RFC1006 formaliza un mecanismo para enviar paquetes a través de un flujo TCP.

Tenga en cuenta que su conmutador, enrutador, swithcgear de ISP ... etc también pueden molestar a sus pequeñas tripas negras. Las pequeñas bestias sucias pueden leer paquetes, por lo que se toman libertades y las reescriben a veces ...

Eche un vistazo a RTP (que se ejecuta a través de UDP) para obtener un enfoque más rentable de la red.

Si tu objetivo es que los barcos terminen haciendo lo mismo en la pantalla de todos, tendrás que enviar actualizaciones de posición. No puedes asumir que solo porque el cliente A lo hizo:

  • girar a la izquierda
  • espera 100ms
  • deja de girar

ese Cliente B verá exactamente el mismo retraso de 100 ms. El búfer de Nagle solo hace que esto sea más extremo, pero siempre habrá fluctuaciones y diferentes retrasos.

Realmente necesitas enviar algo como:

  • (Estoy en la posición X1, Y1 con rumbo Z1) Gire a la izquierda
  • (Estoy en la posición X2, Y2 con rumbo Z2) Detener el giro

Para que los clientes se vuelvan a sincronizar continuamente.

Tenga en cuenta que Windows implementa ACK retrasado , así como Nagle. Esto le puede dar un retraso adicional de 200 ms en los mensajes TCP individuales. Por lo que sé, no puede cambiar esto en Windows excepto a través de una clave de registro (y un hotpatch para habilitar la clave de registro en algunos casos).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top