Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Marvel's Wolverine, la recensione: Logan torna protagonista in un'avventura brutale e intensa
Marvel's Wolverine, la recensione: Logan torna protagonista in un'avventura brutale e intensa
Marvel's Wolverine porta Logan in un'avventura inedita, violenta e fortemente narrativa, costruita attorno alla sua natura di combattente e al difficile rapporto con il proprio passato. Insomniac Games punta su combattimenti spettacolari, progressione e personalizzazione, inserendo l'azione in un mondo segnato dalla persecuzione dei mutanti. Un viaggio intenso, che alterna mattanza, esplorazione e momenti sorprendentemente emotivi.
DJI Romo 2: tante novità lo rendono un robot completo
DJI Romo 2: tante novità lo rendono un robot completo
Romo 2 è la seconda generazione di robot lavapavimenti di DJI, un modello che si caratterizza per la precisione nel sistema di navigazione e per il funzionamento particolarmente silenzioso. Con le modifiche introdotte in questa seconda versione, e un posizionamento di prezzo più allineato alla concorrenza, rappresenta una valida alternativa sul mercato delle soluzioni di pulizia domestica
Sony Bravia 9 II: il True RGB alla prova, dove l'LCD sfida l'OLED
Sony Bravia 9 II: il True RGB alla prova, dove l'LCD sfida l'OLED
Il primo Sony con retroilluminazione True RGB alla prova del banco di misura e dei contenuti: luminanza enorme, colori accurati in HDR e un antiriflesso molto efficace. I limiti sono due sole HDMI 2.1 e il blooming fuori asse
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 09-11-2006, 09:21   #1
Frank1962
Senior Member
 
L'Avatar di Frank1962
 
Iscritto dal: Sep 2001
Città: de_legato
Messaggi: 792
[JAVA]SocketChannel, NoBlocking e read

Ho creato un server java utilizzando la proprietà non bloccante che il ServerSocketChannel offre in modo tale da registrare al Selector tutti i socket che si connettono al mio server con l'opzione 'SelectionKey.OP_READ' in modo tale da sapere quando posso leggere da un socket dei dati che mi arrivano: il dubbio che mi sorge però riguarda all'utilizzo della read per andare a leggere i dati e metterli nel buffer .....devo utilizzare un ciclo while finchè lo stream non mi ritorna -1 per leggere tutti i dati oppue sarà la select che mi ritornerà sempre ogni volta che nel canale rimarranno dei dati da leggere?
In molte implementazioni ho visto che quando la read ritorna -1 si chiude direttamente il canale come se fosse una disconnessione e non come un valore che indica che non ci sono più dati da leggere.
Help pls!

grazie
ciao
__________________
----------------------------------------------
File reality.sys corrupted, Reboot Universe? Y/N
----------------------------------------------
Frank1962 è offline   Rispondi citando il messaggio o parte di esso
Old 09-11-2006, 16:53   #2
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Se intendo correttamente il tuo dubbio, la risposta è "leggi solo i byte disponibili" e non "leggi finchè ci sono byte da leggere".

La lettura è bloccante: se il client vuole trasmettere un gigabyte di macerie e tu tenti di leggerli tutti in una volta il selettore si siede lì e aspetta che tu abbia finito di leggerli.

"non blocking" è l'accettazione delle connessioni. Un ServerSocket bloccante, una volta che abbia ricevuto una connessione, dialoga solo con il Socket connesso a meno che tu non passi il procedimento di gestione della connessione intervenuta ad un Thread diverso.

Il selettore associato ad un ServerSocket non bloccante spezza l'insieme dei procedimenti necessari per la comunicazione in tanti segmenti singolarmente bloccanti e il funzionamento dell'ingranaggio si basa sulla possibilità di dividere quelle operazioni in ulteriori segmenti la cui esecuzione è complessivamente distribuita dal selettore.

Dunque, leggi un numero prefissato di byte per volta, finchè non raggiungi il fatidico meno uno. Ad esempio, ogni volta che il selettore di passa la chiave leggibile, tu tenti di leggere 512 byte. Magari ce ne sono 6, magari ce ne sono cinquemila, ma tu gli fai sputare quelli che può con un solo read e comunque non più di 8, 20 512, un milione, quello che ti sembri il blocco delle dimensioni più opportune:

SocketChannel client = (SocketChannel)currentKey.channel();
FIXED_SIZE_BUFFER.clear();
int read = client.read(FIXED_SIZE_BUFFER);
FIXED_SIZE_BUFFER.flip();
//butti FIXED_SIZE_BUFFER in un secchio di byte associato al canale client

Ora, quando read è menu uno chiudi il canale. Be', non è detto. Dipende se la comunicazione è "spara e dimentica", un po' come per le comunicazioni http, oppure è permanente, come per una chat piuttosto che per un server che ospita la stanza di un gioco on-line.

Se devi trasferire un file e morta lì è chiaro che quando il client o il server ha finito di spedire, termina anche lo scopo della connessione.

Se invece dopo la ricezione del messaggio dal client (read == -1) il client si aspetta una risposta oppure è possibile che il client invii più di un messaggio in tempi diversi, allora la chiave deve permanere.

Puoi scegliere, a quel punto, di cambiare le operazioni a cui la chiave sia interessata (key.interestsOps(SelectionKey.OP_READ) se prima era un OP_WRITE) oppure mantenere la chiave nel selettore, ad esempio nel caso in cui già fosse registrata come OP_READ | OP_WRITE. In quel caso decidi come e quando trasmettere non sulla base dell'interesse dimostrato dalla chiave, ma affindandoti ad una meccanica da te stabilita.
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 09-11-2006, 18:37   #3
Frank1962
Senior Member
 
L'Avatar di Frank1962
 
Iscritto dal: Sep 2001
Città: de_legato
Messaggi: 792
Quote:
Originariamente inviato da PGI-Bis
La lettura è bloccante: se il client vuole trasmettere un gigabyte di macerie e tu tenti di leggerli tutti in una volta il selettore si siede lì e aspetta che tu abbia finito di leggerli.
il problema sorge quando il thread che gestisce il socketchannel che sta inviando i dati è diverso da quello del thread che gestisce il mio ServerSocketChannel ....che succede se mentre il thread gestore del socket sta aspettando per leggere dei dati con una read il serversocketchannel rileva che sono arrivati dei dati disponibili da leggere e passa a un thread servente il socketchannel pensando erroneamente che non ci sia nessuno che sta servendo quel socket?
Un'altra domanda che vorrei porti è se c'è la possibilità di effettuare una read con timeout? ....nel senso che dopo un tot di tempo mi ritorna il controllo anche se non ha effettuato nessuna lettura (in modo tale da chiudere il socket; così come una specie di timeout).
__________________
----------------------------------------------
File reality.sys corrupted, Reboot Universe? Y/N
----------------------------------------------
Frank1962 è offline   Rispondi citando il messaggio o parte di esso
Old 09-11-2006, 20:08   #4
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Con "la lettura è bloccante" intendo dire che se leggi da un socketchannel non bloccante nello stesso modo in cui leggi da un socketchannel bloccante ottieni una lettura bloccante.

Dato un buffer da 100 byte, l'operazione:

socket.read(buffer);

su un socketchannel bloccante tenta di leggere 100 byte. Ma nonostante il "bloccante", può leggerne meno di 100: dipende da quanti byte sono disponibili nel buffer del socketchannel. Così, per leggere 100 byte, diciamo una cosa tipo:

Codice:
int totale = 0;
int read = 0;
while(read = socket.read(buffer) >= 0 && (totale += read) < 100) {
    totale += read;
}
Qui o arrivano 100 byte o arriva un -1, che indica fine delle trasmissioni. Vale la pena notare che il semplice:

socket.read(buffer);

è sì bloccante, ma è bloccante rispetto alla quantità di byte presenti nel buffer del socketchannel al momento dell'invocazione read, non alla quantità di byte che si possono infilare in buffer. La cosa è irrilevante se gestisci un client con un Thread a parte perchè superi il blocco imposto dalla necessità di aspettare che arrivino 100 byte (o che arrivi il -1) proprio dedicando un flusso di esecuzione parallelo a questa attesa.

Per un socketchannel non bloccante il read fa praticamente le stesse cose ma, in teoria, può anche fare di meno: al massimo legge tanti byte quanti ce ne sono nel buffer del socket ma potrebbe benissimo restituire il controllo prima. L'unica cosa che è certa è che non comporta mai un blocco, a prescindere dalle dimensioni del bytebuffer parametro e da quanti byte ci sono nel buffer del socketchannel.

E qui arriva il selettore: con il selettore puoi fare in modo di leggere tutti e 100 i byte senza la necessità che questa operazioni richieda il blocco del Thread che gestisce la comunicazione. A conti fatti, leggi i 100 byte a blocchi: ogni volta che il selettore restituisce la chiave OP_READ associata a quel socketchannel tu leggi tutti i byte che puoi, senza bloccare, fino ad un totale, contando quelli letti nei passaggi precedenti, di 100.

Se vuoi impostare un timeout per un socket non bloccante, tutto quello che devi fare è registrare il momento in cui inizi la lettura e, ogni volta che ti viene data la chiave "isReadable" associata a quel canale, controllare se è spirata la scadenza di lettura (confrontanto il momento in cui esegui un read con il momento in cui hai tentato di leggere qualcosa da quel canale per la prima volta).
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 10-11-2006, 00:46   #5
Frank1962
Senior Member
 
L'Avatar di Frank1962
 
Iscritto dal: Sep 2001
Città: de_legato
Messaggi: 792
Quindi secondo te è lecito che, dopo che la select mi seleziona un socketchannel per la lettura, vado a fare un ciclo while su tale socket finchè non ricevo il fatidico -1? ( while(var!=-1) { } )
E se capita un piccolo "dealy" che, nell'ipotesi di un server web, mi comporta la ricezione a metà di un metodo POST con un messaggio di tot byte e, dopo qualche ms, la ricezione dell'altra metà come mi devo comportare? ...aspettare che la select mi ritorni di nuovo oppure il ciclo while mi "fermerà" il controllo creandomi un piccolo ritardo?
Se consideriamo la lunghezza massima di un segmento TCP, Maximum Segment Size (MSS), come, per esempio, di 1500byte e il metodo POST inviatomi dal client lungo più di 3000byte vorrà dire che per forza di cose i dati che compongono la richiesta http saranno inviati su più segmenti tcp e quindi è plausibile che mi possa capitarmi un dealy un pò "pesante" che vada ad incidere sulla lettura totale della richiesta http .....ecco perchè mi domandavo se c'era la possibilità che nel mezzo della lettura di tale richiesta ci possa essere più di un ritorno della select in lettura.
__________________
----------------------------------------------
File reality.sys corrupted, Reboot Universe? Y/N
----------------------------------------------

Ultima modifica di Frank1962 : 10-11-2006 alle 10:27.
Frank1962 è offline   Rispondi citando il messaggio o parte di esso
Old 10-11-2006, 14:54   #6
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
No perchè quel ciclo blocca il selettore.

La lettura dei byte in arrivo è parziale per definizione, nel senso che la natura non bloccante rende molto più probabile che un messaggio non sia interamente recepito con un solo read(buffer).

Quello che devi fare è, semplicemente, continuare ad accumulare i byte ottenuti da un read per il SocketChannel la cui chiave sia "readable" finchè non incontri un terminatore (ad esempio read restituisce -1).

Per accumulare i byte puoi usare l'allegato della chiave. Un SelectionKey ha un allegato arbitrariamente impostabile. Se, per avventura, quell'allegato fosse un ByteArrayOutputStream (ma è meglio che sia un Channel), quando la chiave restituita dal selettore è "readable" tu diresti:

Codice:
ByteArrayOutputStream allegato =
    (ByteArrayOutputStream)chiave.attachment();
int letti = chiave.channel().read(buffer);
buffer.flip();
//metti i byte di buffer in allegato
if(letti == -1) {
    //passa i byte dell'allegato al processore dei messaggi
}
Crei l'allegato nel momento in cui registri il client presso il selettore che, in sè, è una cosa piuttosto semplice:

Codice:
if(currentKey.isAcceptable()) {
    SocketChannel client = accept(currentKey); //accept qui è un metodo ad hoc
    client.configureBlocking(false);
    SelectionKey clientKey = client.register(...op_read | op_write);
    ByteArrayOuputStream attachment = new ByteArrayOutputStream();
    clientKey.attack(attachment);
}
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 10-11-2006, 18:25   #7
Frank1962
Senior Member
 
L'Avatar di Frank1962
 
Iscritto dal: Sep 2001
Città: de_legato
Messaggi: 792
Quote:
Originariamente inviato da PGI-Bis
No perchè quel ciclo blocca il selettore.

La lettura dei byte in arrivo è parziale per definizione, nel senso che la natura non bloccante rende molto più probabile che un messaggio non sia interamente recepito con un solo read(buffer).

Quello che devi fare è, semplicemente, continuare ad accumulare i byte ottenuti da un read per il SocketChannel la cui chiave sia "readable" finchè non incontri un terminatore (ad esempio read restituisce -1).
.....
si ma prendiamo un esempio: se il client deve mandare un messaggio POST di dimensioni addirittura maggiori al buffer tcp di trasmissione del client stesso può capitare che il processo server si trovi con una read che ritorna -1 anche se in realtà non è arrivato tutto il messaggio di post? (nel senso che nell'effettuare un write su un socket, quindi nel buffer tcp di trasmissione, questa può bloccarsi per un pò se i dati che gli sono passati come argomento sono di dimensioni maggiori dello spazio libero disponibile in quel momento nel buffer)
è strano come in molti libri anche di ultima pubblicazione non venga trattato l'argomento dei socket non bloccanti, nel testo "Java manuale ufficiale" alla 4° edizione l'argomento non è minimamente toccato come del resto l'utilizzo della classe Selector!
__________________
----------------------------------------------
File reality.sys corrupted, Reboot Universe? Y/N
----------------------------------------------

Ultima modifica di Frank1962 : 10-11-2006 alle 18:43.
Frank1962 è offline   Rispondi citando il messaggio o parte di esso
Old 11-11-2006, 01:16   #8
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Il -1 significa "end of stream", non "end of message". Cosa significhi "end of stream" per un Socket non è propriamente determinato. Ad esempio sappiamo che -1 è il valore ottenuto da un read sul canale di un socket per cui sia stato invocato "shutdownInput".

E' possibile che arrivi un -1 quando si legga da un Socket pur avendo questi ancora byte da inviare? Direi di no ma, sai com'è, tecnologia, magia...

Comunque -1 in lettura non significa che il SocketChannel sia da chiudere. In un SocketChannel è bidirezionale: ha due piste, una in lettura e una in scrittura. Nulla vieta che il flusso in del socket sia chiuso e quello out sia aperto. E' evidente, pertanto, che una chiusura dell'intero socket nel caso in cui la lettura restituisca -1 è fatta sulla base dell'assunto che lo scopo della connessione sia assolto al termine dell'invio (o ricezione, dipende se la vediamo dal lato client o server) del messaggio.

Se conti sulla capacità del client di trasmettere più d'un messaggio non userai -1 come terminatore esclusivo ma come terminatore eventuale. Imponi una condizione principale che segnali la ricezione dei byte necessari e sufficienti alla ricostruzione del messaggio inviato fondata su una convenzione.

Ad esempio, puoi stabilire che i messaggi abbiano la forma:

[4 byte = N][N byte]

cioè ogni messaggio inizia con un intero indicante il numero di byte che costituiscono il messaggio. A questo punto leggerai i primi quattro byte, determinerai N e, una volta ricevuti, applicherai un insieme di letture successive che termineranno quando il totale di byte letti sia pari a N.

Oppure usi un carattere ASCII, il tipico "new line indica fine del messaggio".

O usi la convenzione HTTP: anche lì ci sono una miriade di norme che determinano "quando un messaggio può considerarsi concluso" che nulla hanno ovviamente a che fare con il -1.
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Marvel's Wolverine, la recensione: Logan torna protagonista in un'avventura brutale e intensa Marvel's Wolverine, la recensione: Logan torna p...
DJI Romo 2: tante novità lo rendono un robot completo DJI Romo 2: tante novità lo rendono un ro...
Sony Bravia 9 II: il True RGB alla prova, dove l'LCD sfida l'OLED Sony Bravia 9 II: il True RGB alla prova, dove l...
Geely EX5, un mese al volante: il SUV elettrico cinese che ci ha sorpreso (quasi) senza riserve Geely EX5, un mese al volante: il SUV elettrico ...
Mova Z70 Ultra Roller Complete: motore potente, rullo di lavaggio e l'IA a guidare Mova Z70 Ultra Roller Complete: motore potente, ...
Avio si prepara ai test del Dimostratore...
Space Pioneer ha annunciato le cause del...
Anthropic avrebbe nuovi antibiotici cont...
Scoperto un 'moltiplicatore nascosto' ne...
DREO: a IFA 2026 4 novità fra cui...
Slackbot genera dashboard e microsite de...
Idrogeno, nuova cella a combustibile rag...
Con la NASA fuori dai giochi, l'ESA risc...
Una falla di ChatGPT permette di estrapo...
Piano clima, 1,34 miliardi per il bonus ...
Porsche esce definitvamente da Bugatti R...
NVIDIA App aggiunge una delle funzioni p...
Come sarebbe il mondo se la luce viaggia...
Titanio, ceramica e zaffiro per HUAWEI W...
Taglio delle accise sul gasolio prorogat...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 05:03.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Served by www3v