Ho bisogno di trovare una soluzione per l'interleaving dei dati di rete ad alto throughput nella mia applicazione Windows basata su framework QT.
La mia applicazione si basa sull'architettura server / client. Il client si connette a un server ed entrambi possono scambiare messaggi di dimensioni arbitrarie. Un messaggio è solo un pezzo di dati, con un'intestazione che descrive il messaggio.
È necessario considerare le seguenti limitazioni:
- La dimensione del messaggio è nota in anticipo sul sito del mittente (sul sito del destinatario dopo aver ricevuto l'intestazione del primo messaggio)
- Esiste solo un flusso di rete (una porta aperta)
- Protocollo orientato alla connessione (TCP / IP) se possibile
- Connessione di rete wireless (WLAN) (in genere 5-10 MB / s throughput netto)
- I messaggi devono essere inviati il più velocemente possibile
- I messaggi di grandi dimensioni potrebbero non bloccare i messaggi più piccoli
Poiché può esistere un solo flusso di dati (per connessione), ho deciso di utilizzare l'intercalazione dei dati in modo che un messaggio di grandi dimensioni non possa bloccare diversi messaggi più piccoli. A tale scopo, permetto la frammentazione del messaggio e ho introdotto una priorità di messaggio di 3 classi. L'intestazione del messaggio contiene le dimensioni totali, l'offset del carico utile e le dimensioni del payload in modo che l'assemblaggio di un messaggio interfogliato sia possibile sul sito del destinatario.
Esempio di messaggi di grandi dimensioni:
- Stream video
- Aggiornamento firmware
Esempi di piccoli messaggi:
- Messaggi di stato (carico di lavoro, stato della batteria, ...)
- Messaggi di comando
Un approccio ingenuo sarebbe quello di inviare via tutti i messaggi di seguito. Tuttavia, ciò bloccherebbe i messaggi ad alta priorità più piccoli per un certo periodo di tempo poiché i messaggi di dati del flusso video, ad esempio, utilizzano la connessione di rete al massimo. Questo non sarebbe accettabile. Invece di inviare un messaggio in una parte, ho deciso di dividere tutti i messaggi e dividerli in blocchi di 8 KB di grandi dimensioni. Anche se non ho idea di come possa interlacciare in modo ottimale i singoli frammenti di messaggi l'uno nell'altro, penso che ci siano diverse strategie di sheduling che possono essere usate qui. Tuttavia, questo non è un mio problema.
+----------------------------------+
| Message |
+--+-------------------------------+
| | Header 1 |
+--+-------------------------------+
| | Payload (max. 8 KB) |
+--+-------------------------------+
| ... |
+--+-------------------------------+
| | Header N |
+--+-------------------------------+
| | Payload (max. 8 KB) |
+--+-------------------------------+
Indovina, ad un certo punto nel tempo, c'è un singolo messaggio molto grande che deve essere inviato. Non ci sono altri messaggi nella coda di uscita! Quindi non c'è nulla da intercalare qui. Un approccio ingenuo sarebbe quello di mandare via quel messaggio. Tuttavia, dopo aver iniziato a inviare questo messaggio di grandi dimensioni, alcuni piccoli messaggi ad alta priorità vengono messi in coda. Tuttavia, poiché il messaggio di grandi dimensioni è già stato inviato al socket, questi nuovi messaggi di piccole dimensioni devono attendere fino a quando non è stato inviato il messaggio di grandi dimensioni. Questo caso dovrebbe essere prevenuto!
Ho avuto molte idee diverse, ma nessuna era soddisfacente.
L'idea era di fornire solo tanti dati sul socket che non fossero a corto di dati, ma non tanto che nel buffer del socket ci fossero troppi dati. Ciò garantirebbe che in qualsiasi momento i dati più piccoli possano essere inseriti nel flusso di dati senza grandi ritardi. Il problema è, come posso scoprire quanti dati sono ottimali in modo che il throughput sia ancora al massimo? Come posso essere informato che i dati sono stati inviati e quanti dati sono rimasti nel buffer del socket?
Mi sono perso qualcosa? C'è anche una soluzione migliore? Sono aperto a nuove / migliori idee.
Modifica: qualche altro chiarimento
Anche l'idea di riempire le code prioritarie e inserire blocchi di priorità maggiore davanti ai blocchi a bassa priorità è stata presa in considerazione da me. Il problema che si verifica è il seguente:
Devo trattenere blocchi di dati in una coda e non posso inviarlo troppo velocemente al socket. Quindi, una volta nel buffer del socket non ho più controllo su di esso. Ciò può portare alla situazione in cui ci sono abbastanza dati da inviare, ma il socket esaurisce i dati e è inattivo. Ciò ridurrà il throughput dei dati. Come posso determinare lo stato di riempimento ottimale del buffer del socket in modo che il socket non esaurisca i dati? Il problema potrebbe anche peggiorare, per quanto ne so, non è possibile informarsi sullo stato del buffer, né se sono stati inviati tutti i dati, né quanti dati sono rimasti nel buffer del socket per l'invio.