View Full Version : [Java] OutputStream limitare la banda di uscita...
...ciao...
...come da titolo avrei la necessità di imporre un limite nell'utilizzo della banda da parte di un OutputStream...la soluzione che sto usando ora è quella di aggiungere uno sleep ad ogni invio del buffer. Questo modo pero' mi crea un andamento a dente di sega ed inolte non mi permette di limitare in maniera precisa la banda utilizzata...
...idee per una possibile soluzione?...
...ciao Andrea...
banryu79
25-05-2009, 17:04
Potresti usare un BufferedOutputStream.
Tale classe fornisce un costruttore che ti permette di specificare la grandezza in byte del buffer interno.
Quando si inviano in scrittura dei byte a tale BufferedOutputStream, questi in realtà non vengono spediti allo stream sottostante finchè possono essere appesi al buffer interno; quando si raggiunge il limite di capacità del buffer interno, questo viene "flushato" cioè i byte che contiene vengono effettivamente inviati allo stream sottostante (il che in genere significa generare attività di sistema).
Se tu puoi stabilire la grandezza del buffer interno (usando l'apposito costruttore), puoi in pratica porre un 'tetto limite' al numero massimo di byte scritti ognivolta che parte nell'effettivo un'operazione di scrittura.
Il fatto è che per controllare il numero massimo di bytes spediti in un certo lasso di tempo dovresti estenderti BUfferedOutputStream e dotarlo di un timer o analogo che non permetta di flushare il buffer interno se non è passato un intervallo di tempo stabilito dall'ultimo flush.
Se viene invocato un flush, e l'intervallo stabilito deve ancora passare, bisognerà comunque memorizzare i dati inviati da qualche parte, per non perderli, per esempio con una riallocazione con copia del buffer di byte interno (per esempio raddoppiando le dimensioni, oppure usando un altro fattore che viene specificato al momento della creazione dello stream).
In questo caso bisogna assicurarsi che l'operazione di flush scriva sempre lo stesso quantitativo di bytes [tranne nell'ultimo flush, quello che viene fatto tipicamente all'invocazione del metodo di chiusura di uno stream], in modo che in caso di riallocazione del buffer interno comunque si scrivano nello stream sottostante sempre lo stesso numero di bytes.
Non so se in linea di massima è quello che cercavi...
Ti allego un link al codice di java.io.BufferdOutputStream (http://www.docjar.com/html/api/java/io/BufferedOutputStream.java.html), guardando il quale mi è venuta in mente la soluzione che ti ho abbozzato.
Probabilmente esistono medoti migliori, ma io non saprei.
...ciao...
...come da titolo avrei la necessità di imporre un limite nell'utilizzo della banda da parte di un OutputStream...la soluzione che sto usando ora è quella di aggiungere uno sleep ad ogni invio del buffer. Questo modo pero' mi crea un andamento a dente di sega ed inolte non mi permette di limitare in maniera precisa la banda utilizzata...
...idee per una possibile soluzione?...
...ciao Andrea... piazza un FilterOutputStream, conta i bytes che viaggiano e se superano il limite di bytes al secondo attendi lo scatto della prossima "finestra" di gestione temporale.
lo rispiego meglio :D
hai un thread a parte che scatta ogni secondo e ogni volta che scatta parte questa "finestra" di gestione della banda che dura un secondo.
poi nella tua implementazione di FilterOutputStream hai un campo intero che é un contatore che dice il numero di bytes di banda ancora disponibili per quella finestra temporale.
nel FilterOutputStream tu hai sovrascritto la versione fondamentale di write che scrive un solo byte (quella che viene richiamata da tutte le altre versioni, poi se vuoi fare un'implementazione piu efficiente sovrascrivi anche tutte le altre); il codice della tua write controlla il valore del contatore dei bytes rimasti: se é zero blocca il thread fino alla prossima finestra temporale, altrimenti lo decrementa di uno ed invia il byte.
dettagli:
1. come viene inizializzato il contatore? precisamente al valore della banda di upload che tu vuoi concedere :)
2. quando viene inizializzato il contatore? viene resettato al valore di banda in upload ad ogni "scatto di finestra"
3. come fare all'interno della write, quando il contatore é zero, ad attendere che arrivi una nuova finestra e che quindi il contatore ritorni al valore di banda concessa? banalmente attendi su un oggetto qualunque col metodo Object.wait; l'altro thread, quello che "da il passo", chiama Object.notify ogni volta che scatta una finestra, non prima di aver resettato il contatore naturalmente.
...grazie per la risposta...ma nell'OutputStream faccio già uso di un buffer impostato da me...il problema è che periodicamente stoppare il flush del buffer con uno sleep per limitare la banda in uscita dando sulla rete un utilizzo a dente di sega : picco di invio e pausa > picco di invio e pausa > etc...cercavo un modo piu' elegante per rendere l'invio uniforme e bloccato ad una velocità specifica...
...ciao Andrea...
altro consiglio: per far si' che questo tuo FilterOutputStream venga effettivamente utilizzato potresti creare delle tue sottoclassi di Socket e ServerSocket i cui metodi getOutputStream restituiscono il tuo FilterOutputStream costruito al di sopra di super.getOutputStream().
potrebbe anche essere il caso di rimpiazzare la socket factory predefinita.
...grazie per la risposta...ma nell'OutputStream faccio già uso di un buffer impostato da me...il problema è che periodicamente stoppare il flush del buffer con uno sleep per limitare la banda in uscita dando sulla rete un utilizzo a dente di sega : picco di invio e pausa > picco di invio e pausa > etc...cercavo un modo piu' elegante per rendere l'invio uniforme e bloccato ad una velocità specifica... l' "invio uniforme" non esiste per natura di TCP/IP: comunque sia il software alla fine raccoglie tutto e quando ha raccolto abbastanza manda un pacchetto intero.
secondo me attendere del tempo dopo ogni invio non é affatto una cattiva soluzione, peró la variante che ti ho proposto io é un po' piu elegante perché anziché attendere un tot esatto di tempo tra un invio e l'altro attendi solo il tempo che resta affinché cominci la nuova finestra temporale.
banryu79
25-05-2009, 17:41
...il problema è che periodicamente stoppare il flush del buffer con uno sleep per limitare la banda in uscita dando sulla rete un utilizzo a dente di sega : picco di invio e pausa > picco di invio e pausa > etc...
Proprio per questo motivo avevo ipotizzato l'utilizzo non del FilterOutputStream ma di un BufferedOutputStream (che poi è un'estensione di FilterOutputStream) customizzato nella gestione del flushing del buffer interno...
@EDIT:
magari non è importante ma il fatto è che, se non erro, la chiamata ai metodi write è bloccante, per quello ho preferito evitare ma in effetti non è detto che col buffer te la cavi meglio; meriterebbe una prova empirica però.
Proprio per questo motivo avevo ipotizzato l'utilizzo non del FilterOutputStream ma di un BufferedOutputStream (che poi è un'estensione di FilterOutputStream) customizzato nella gestione del flushing del buffer interno...
...si scusa e scusate...il caldo miete vittime...devo controllare in maniera migliore il rilascio del buffer...ora attendo il raggiungimento del valore massimo per l'unita di tempo (1s) prima di entrare entrare eventualemente nello sleep...giustamente dovrei controllare il rilascio del buffer ad ogni passaggio per evitare il picco di utilizzo di banda...analizzando così l'invio dei dati in porzioni di tempo inferiori...
...ora...si spera...mi è chiaro...
...grazie Andrea...
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.