NIO - Selector

Status
Nicht offen für weitere Antworten.

Kr0e

Gesperrter Benutzer
Hallo,
mir ist gerade was sehr merkwürdiges aufgefallen:
Ich habe 2 UDP-Channels auf OP_READ registriert... nun registriere ich einen Channel auf OP_WRITE,
damit ich 400 bytes an den anderen schicken kann, sobald der andere Channel "readable" ist, starte ich einen
Thread der vom Channel 4 bytes liest und sie dann auswertet. Bevor ich den Thread starte, deregistriere ich diesen
Channel von OP_READ, damit nicht parallel von 1 Channels gelesen wird... Danach registriere ich ihn wieder auf
OP_READ, allerdings wird dieses Ereignis nie wieder ausgelöst, obwohl ansich noch 396 Bytes im Netzwerk buffer schlummern müssten oder nicht ? "Warum lagere ich das Lesen in einen Thread aus ?" -> Damit der Overhead vom
Erstellen eines Buffers und lesen von diesem Buffer nicht die Selector Schleife aufhält.... Aber wenn das so nicht klappt,
dann werde ich dieses Modell nochmal überdenken müssen..... Also ist das normal, oder kann es sein, dass cih einfach nur einen Codefehler hab ? ICh würde gerne posten, aber das sind sehhhr viele Seiten...

Gruß Chris
 
T

tuxedo

Gast
>> Bevor ich den Thread starte, deregistriere ich diesen
Channel von OP_READ, damit nicht parallel von 1 Channels gelesen wird... Danach registriere ich ihn wieder auf
OP_READ

?? Versteh ich nicht. Di registrierst das ganze auf "READ". Und wenn das Event kommt, dann de-registrierst du ihn und delegierst das lesen der 400 bytes in einen Thread. Soweit okay. Aber erst wenn du deine 400 Bytes gelesen hast triggerst du wieder rein registrieren auf "READ".

>> obwohl ansich noch 396 Bytes im Netzwerk buffer schlummern müssten oder nicht ?

woher sollen wir das denn wissen? Du hast drei Möglichkeiten:

1) Du liest das Paket komplett:

- Registrieren für "READ"
- Warten bis Event kommt
- "READ" de-registrieren
- im Thread volle 400 bytes einlesen
- Thread triggert nach dem lesen der 400 bytes das registrieren auf "READ"

2) Du liest Stückchenweise dein 400 Byte Paket, Variante 1

- Registrieren für "READ"
- Warten bis Ebent kommt
- "READ" de-registrieren
- Im Thread so viel lesen wie von den 400 bytes schon da ist und dies an eine bestimmte Stelle ablegen
- Thread triggert das registrieren auf "READ"
- Im select() loop auf nächstes Event warten

3) Du liest Stückchenweise dein 400 Bytes Paket, Variante 2

- Registrieren für "READ"
- Warten bis Ebent kommt
- Im Thread so viel lesen wie von den 400 bytes schon da ist und dies an eine bestimmte Stelle ablegen
- Im select() loop auf nächstes Event warten

Nummer 1 und 2 arbeiten sequentiell. D.h. es kann am Paket nichts durcheinander kommen (was bei TCP etwas kritisch ist und bei UDP sowieso manuell gehandhabt werden muss). Nummer 3 kann parallel lesen. Je nachdem wie schnell die einzelnen Lese-Threads sind, können die Pakethäppchen beim ablegen an bestimmter Stelle durcheinander kommen.

Ich bevorzuge Variante 1. Die funktioniert bei mir und die lässt sich noch am einfachsten debuggen.

Ist jetzt halt die Frage wann du du den Channel wieder für "READ" selektierst und warum nur 4 bytes gelesen wurden?!

- Alex
 

Kr0e

Gesperrter Benutzer
Nagut, Variante 1) sagt mir auch zu ... Obwohl 2 auch gut ist ... je nach Anwendung ...
ICh war mir einfach nicht sicher, wie genau der Selector intern arbeitet, ich dachte einfach es wäre ein bisschen wie bei
C++ / Sockets, denn mit der Funktion recv laß man dann einen bestimmten satz aus dem puffer und danach war dieser dann leer, bzw in meinem beispiel wären dann dort noch 396 bytes drin... Aber wenn man z.b. read aufruft, wird anscheinend nur eine Kopie des Buffers erstellt und entsprechend der Größe des ByteBuffers kopiert... Ich meine halt einfach, dass das OP_READ Event ansich auch ausgelöst werden sollte, bei Selector.select(), da ja noch daten vorhanden sind... aber wenn sowieso nur eine Kopie erstellt wird, dann ist dies nicht der Fall. Ich kam durcheinander, weil ich irgendwie in Errinnerung hab, dass das bei der select funktion (Socket API) ging... naja Danke!


Gruß Chris
 
T

tuxedo

Gast
Ach so. Denke ich hab dein Problem erst jetzt verstanden:

Du bekommst ein READ Event und liest von den 400 bytes bewusst nur 4 aus. Danach registrierst du dich wieder für READ und erwartest dass dann erneut ein READ event auftaucht das dich an weitere 396 Bytes erinnert?! Hmm. Ob das geht? Ich glaub nicht.

Der Empfangspuffer müsste per Default 8k fassen. Und ein READ Event wird nur ausgelöst, wenn Daten eingehen. Gehen auf einen Schlag 400 bytes ein, so löst das auch nur ein Event aus. Und ich glaub da liegt unter anderem das Problem:

Entweder man liest soviel wie da ist, oder man liest mehr und muss ggf. warten bis mehr angekommen ist. Aber weniger lesen als eingetroffen ist und dann ohne weiteren Dateneingang auf ein weiteres Event mit "Daten sind da" zu warten.. Denke da wartest du, bzw. deine Anwendung lange ;-)

Wenn du nicht gleich die vollen 400 Bytes verarbeiten willst, solltest du diese in einen Zwischenpuffer stecken. Aber ich denke die Fausregel: "Lies soviel wie da ist" sollte man nicht unbedingt brechen.

Bin mir aber bei der Sache nicht 100,00% sicher. Könnte auch sein dass ich mich täusche und bereits vorhandene Daten, welche noch nicht gelesen sind, mit irgend einem Trick nochmal READ auslösen. Aber wenn, dann ist mir das nicht bekannt (und ich hab viel zu NIO gelesen. Im Buch "Java NIO" von Ron Hitchens steht glaub auch nix dazu (oder ich habs überlesen)).

- Alex
 
Status
Nicht offen für weitere Antworten.

Ähnliche Java Themen


Oben