Domanda

Sto scrivendo un server socket e un client di gioco flash. Il gioco richiede comandi in tempo reale come movimento e svolta. È importante che questi comandi vengano inviati dal server al client il più presto possibile perché gli altri client si disincronizzerebbero molto con il client di spostamento / rotazione.

Questo è un esempio del problema causato dall'aritmetica di Nagle:

Nota : vedere la tabella dei comandi di seguito se si desidera comprendere il significato di questi comandi.

La prima è la nave che ho spostato (spostato in avanti + a destra, in avanti è stato ricevuto ma non a destra)

I comandi di invio 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

Il client che riceve i comandi:

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 " è un termine strano che non significa ciò che sto cercando di dire, ma qui sembra la quantità di tempo in millisecondi dopo il comando precedente

  1. vai avanti inviare dal cliente A (momento: 0), ricevuto dal cliente B (momento: 0)

  2. svolta a destra inviare dal cliente A (momento: 0), ricevuto dal cliente B (momento: 155)

  3. smette di muoversi inviare dal cliente A (momento: 108), ricevuto dal cliente B (momento: 0)

  4. smette di girare inviare dal cliente A (momento: 0), ricevuto dal cliente B (momento: 0)

  5. vai avanti inviare dal cliente A (momento: 1283), ricevuto dal cliente B (momento: 1236)

  6. svolta a destra inviare dal cliente A (momento: 1), ricevuto dal cliente B (momento: 273)

  7. interrompe il movimento inviare dal cliente A (momento: 186), ricevuto dal cliente B (momento: 0)

  8. smette di girare inviare dal cliente A (momento: 30), ricevuto dal cliente B (momento: 0)

Questa è la tabella dei comandi corrispondente ai comandi:

Client- > Server

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

Server- > 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

Quindi, ciò che puoi vedere è che i comandi sono totalmente desincronizzati a causa di " Nagle " ;. Questo fa sì che il comando di arresto del movimento venga ricevuto da altri client contemporaneamente al comando di avvio del movimento, impedendo a quel giocatore di muoversi affatto.

Ecco perché ho bisogno che questi comandi vengano inviati in tempo reale, il più velocemente possibile dal server TCP. Una soluzione semplice sarebbe disabilitare semplicemente Nagle. Tuttavia, ho googled (nota che il suo suggerimento su tcp message partial è implementato nel mio sistema ma non ha nulla a che fare con il timing) e ha notato che le persone non raccomandano assolutamente di disabilitare Nagle.

È vero che non dovrei disabilitare l'algoritmo Nagle per questa causa e dovrei invece cercare un'altra soluzione? Perché (no)?

Grazie in anticipo. - Tom

È stato utile?

Soluzione

Si desidera utilizzare TCP_NODELAY per disattivare l'algoritmo nagle per quel socket. Esistono impostazioni nei moderni sistemi operativi per disabilitarlo a livello di sistema e che È disapprovato, ma non c'è motivo per cui non dovresti farlo con un socket che SAPI che hai bisogno di bassa latenza su .

setsockopt (TCP_NODELAY)

Altri suggerimenti

Se deve essere il più veloce possibile, dovresti usare UDP.

Tuttavia, si noti che TCP fornisce la garanzia di consegna e ordine mentre UDP non ne fornisce alcuna.

Quel punto sembrerebbe essere un punto critico in questa applicazione, quindi dovresti sovrapporre il tuo meccanismo di ordinamento dei comandi di riconoscimento / riprova.

Se vuoi restare con TCP, TCP__NODELAY ti aiuterà. Man mano che il gioco avanza, potresti finire per richiedere un flusso di dati a cui TCP sarà adatto senza TCP_NODELAY.

RFC1006 formalizza un meccanismo per l'invio di pacchetti su un flusso TCP.

Nota che il tuo switch, router, swithcgear dell'ISP .... ecc. potrebbero anche far sparire le loro viscere nere. Le bestie sporche possono leggere i pacchetti, quindi prendono le libertà e le riscrivono a volte ..

Dai un'occhiata a RTP (che funziona su UDP) per un approccio più sostenibile alla rete.

Se il tuo obiettivo è far sì che le navi finiscano per fare la stessa cosa sullo schermo di tutti, dovrai inviare gli aggiornamenti di posizione. Non puoi supporre che solo perché il client A ha fatto:

  • Svoltare a sinistra
  • Attendi 100 ms
  • Smetti di girare

che il Cliente B vedrà esattamente lo stesso ritardo di 100 ms. Il buffering di Nagle rende questo più estremo, ma ci saranno sempre jitter e ritardi variabili.

Devi davvero inviare qualcosa del tipo:

  • (Sono nella posizione X1, Y1 con la direzione Z1) Svoltare a sinistra
  • (Sono nella posizione X2, Y2 con la direzione Z2) Smetti di girare

In modo che i client si risincronizzino continuamente.

Nota che Windows implementa ACK ritardato e Nagle. Questo può darti ulteriori 200ms di ritardo sui singoli messaggi TCP. Per quanto ne so, non è possibile modificarlo su Windows se non tramite una chiave di registro (e un hotpatch per abilitare la chiave di registro in alcuni casi).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top