Utilisation de TCP pour les commandes en temps réel: L'algorithme Nagle provoque de très longs retards, que dois-je faire?

StackOverflow https://stackoverflow.com/questions/1609880

Question

J'écris un serveur de socket et un client de jeu flash. Le jeu nécessite des commandes en temps réel telles que le mouvement et les virages. Il est important que ces commandes soient envoyées par le serveur au client dès que possible car, sinon, les autres clients désynchroniseront beaucoup de choses avec le client en mouvement / tournant.

Voici un exemple du problème causé par l'arithmétique de Nagle:

Remarque : consultez le tableau des commandes ci-dessous si vous souhaitez comprendre la signification de ces commandes.

Le premier est le navire que j'ai déplacé (avancé + droit, le reçu a été reçu mais pas le droit)

Commandes d'envoi du client:

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

Le client qui reçoit les commandes:

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

"moment" est un terme étrange qui ne signifie pas ce que je veux dire, mais ici, il semble que la durée en millisecondes après la commande précédente

  1. aller de l'avant envoyer par le client A (moment: 0), reçu par le client B (moment: 0)

  2. tournez à droite envoyer par le client A (moment: 0), reçu par le client B (moment: 155)

  3. arrêter de bouger envoyer par le client A (moment: 108), reçu par le client B (moment: 0)

  4. arrête de tourner envoyer par le client A (moment: 0), reçu par le client B (moment: 0)

  5. aller de l'avant envoyé par le client A (moment: 1283), reçu par le client B (moment: 1236)

  6. tournez à droite envoyer par le client A (moment: 1), reçu par le client B (moment: 273)

  7. arrêter le mouvement envoyé par le client A (moment: 186), reçu par le client B (moment: 0)

  8. arrête de tourner envoyer par le client A (moment: 30), reçu par le client B (moment: 0)

Il s'agit de la table de commandes correspondant aux commandes:

Client- > Serveur

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

Serveur- > Client

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

Donc, vous pouvez voir que les commandes sont totalement désynchronisées à cause de "Nagle". Cela fait en sorte que la commande d'arrêt du mouvement soit reçue par les autres clients en même temps que la commande de démarrage du mouvement, ce qui empêche le joueur de se déplacer.

C'est pourquoi j'ai besoin que ces commandes soient envoyées en temps réel, aussi rapidement que possible par le serveur TCP. Une solution facile serait simplement de désactiver Nagle. Cependant, j'ai recherché sur Google (notez que sa suggestion concernant tcp Le message partiel est implémenté dans mon système mais n'a rien à voir avec le timing) et a remarqué que les gens ne recommandent absolument pas de désactiver Nagle.

Est-il vrai que je ne devrais pas désactiver l'algorithme de Nagle pour cette cause mais que je devrais plutôt rechercher une autre solution? Pourquoi (pas)?

Merci d'avance. - Tom

Était-ce utile?

La solution

Vous voulez utiliser TCP_NODELAY pour désactiver l'algorithme nagle pour ce socket. Dans les systèmes d’exploitation modernes, il existe des paramètres permettant de le désactiver sur l’ensemble du système, et IS l’ignorant, mais il n’ya aucune raison de ne pas le faire avec une prise dont VOUS POUVEZ SAVOIR avoir besoin d’une faible latence .

setsockopt (TCP_NODELAY)

Autres conseils

S'il doit être aussi rapide que possible, vous devez utiliser UDP.

Toutefois, notez que TCP fournit la garantie de livraison et de commande , tandis que UDP n'en fournit aucune.

Ce point semble être un point important dans cette application, vous devez donc superposer votre propre mécanisme de commande de reconnaissance / relance.

Si vous voulez rester avec TCP, TCP__NODELAY vous aidera. Au fur et à mesure que votre jeu avance, vous risquez de nécessiter un flux de données que TCP conviendra parfaitement sans TCP_NODELAY.

La RFC1006 formalise un mécanisme d'envoi de paquets sur un flux TCP.

Notez que votre commutateur, votre routeur, le swithcgear du FAI, etc., etc. peuvent tous aussi déranger leurs petits tripes noires. Les petites bêtes sales peuvent lire les paquets, elles prennent donc des libertés et les réécrivent parfois.

Jetez un coup d’œil à RTP (qui fonctionne sur UDP) pour une approche plus viable en réseau.

Si votre objectif est de faire en sorte que les navires finissent par faire la même chose sur l’écran de chacun, vous devrez envoyer des mises à jour de position. Vous ne pouvez pas supposer que simplement parce que le client A a fait:

  • Tourner à gauche
  • Attendez 100ms
  • Arrêtez de tourner

ce client B verra ce même délai de 100ms exactement. La mise en mémoire tampon de Nagle rend la situation encore plus extrême - mais il y aura toujours de la gigue et des retards variables.

Vous devez vraiment envoyer quelque chose comme:

  • (Je suis en position X1, Y1 avec le titre Z1) Tourner à gauche
  • (Je suis en position X2, Y2 avec la rubrique Z2) Arrêter de tourner

Pour que les clients se resynchronisent en permanence.

Notez que Windows implémente les ACK retardé ainsi que Nagle. Cela peut vous donner un délai supplémentaire de 200 ms sur des messages TCP individuels. Autant que je sache, vous ne pouvez pas changer cela sous Windows, si ce n'est via une clé de registre (et un correctif pour activer la clé de registre dans certains cas).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top