NIO Channels SYSTEM SOFTWARE 1
Networking Grundlagen Channels und Buffers Nicht-blockierendes Arbeiten mit Selectors Asynchrone Channels Locks SYSTEM SOFTWARE 2
Motivation Mit NIO und NIO.2 wurden Channels als Alternative zu Input/OutputStreams eingeführt Channels bieten ein elementares API (low-level API) unterstützen effizienteres Lesen und Schreiben auf Files und Sockets erlauben asynchrone Verarbeitung Operationen der Input/OutputStreams sind heute mit Channels im Hintergrund realisiert Package java.nio.channels SYSTEM SOFTWARE 3
Konzepte Channels: Channels werden von Datenquellen und senken Files Sockets erzeugt und erlauben dann bidirektionales Lesen und Schreiben Buffer: Channels arbeiten grundsätzlich mit Buffer; folgende Buffer werden unterstützt: ByteBuffer CharBuffer ShortBuffer IntBuffer LongBuffer FloatBuffer DoubleBuffer Selectors: Selectors erlauben auf mehrere Channels zu horchen und damit in einem Thread mehrere Channels zu bedienen Asynchronous Channels für asynchrone Verarbeitung Locken von Dateien über Channels SYSTEM SOFTWARE 4
Networking Grundlagen Channels und Buffers Nicht-blockierendes Arbeiten mit Selectors Asynchrone Channels Locks SYSTEM SOFTWARE 5
Channels Channels werden von Files oder Input/OutputStreams erzeugt Zum Beispiel durch: Files.newByteChannel(Path path) try ( ByteChannel srcchnl = Files.newByteChannel(srcPath, StandardOpenOption.READ); ByteChannel destchnl = Files.newByteChannel(destPath, StandardOpenOption.WRITE); ) { Des Weiteren gibt es eine Vielzahl von Methoden, die Channels mit unterschiedlichen Eigenschaften erzeugen Channel Zoo: Interfaces: ByteChannel, ReadableByteChannel, WritableByteChannel, SeekableByteChannel, ScatteringByteChannel, GatheringByteChannel, AsynchronousByteChannel, AsynchronousChannel,... Classes: FileChannel, SocketChannel, ServerSocketChannel, AsynchronousFileChannel, AsynchronousSocketChannel, AsynchronousServerSocketChannel, DatagramChannel, SelectableChannel,... SYSTEM SOFTWARE 6
Lesen und Schreiben mit Channels Lesen und Schreiben erfolgt grundsätzlich über Buffer, d.h., es wird in Buffer gelesen und von Buffer geschrieben -1 für End of Stream int bytesread = channel.read( buffer ); int byteswritten = channel.write( buffer ); Buffers sind eine Abstraktion von Arrays mit spezieller API für Channels Bufffer werden über statische Methoden allokiert ByteBuffer buffer = ByteBuffer.allocate( 1024 ); Channel Buffer write read Data source/sink SYSTEM SOFTWARE 7
Buffer API Channel Wesentliche Methoden bei Buffers: put: Füllen eines Buffers mit Daten put get Buffer write read Data source/sink public ByteBuffer put(byte[] src) public ByteBuffer put(byte[] src, int offset, int length) public ByteBuffer put(bytebuffer src) get: Lesen der Daten aus Buffer public byte get() public ByteBuffer get(byte[] dst) public ByteBuffer get(byte[] dst, int offset, int length) public byte get(int index) public char getchar() public double getdouble()... clear: Löschen des Inhalts public final Buffer clear() flip und rewind: Lese- und Schreibposition zurückstellen public Buffer flip() public Buffer rewind() SYSTEM SOFTWARE 8
Buffer API Eigenschaften: capacity: Kapazität des Buffers public int capacity() position: Aktuelle Lese- oder Schreibposition public int position() public Buffer position(int newposition) limit: Position, wie weit Buffer geschrieben oder gelesen werden kann public int limit() public Buffer limit(int newlimit) SYSTEM SOFTWARE 9
Arbeitsweise Buffer Interpretation von position und limit abhängig, ob vom Buffer gelesen (Read Mode) oder in den Buffer geschrieben (Write Mode) wird Write Mode: position: nächste Position für neues Zeichen limit: gleich capacity Read Mode: position: nächste Position zum Lesen limit: bis wohin gelesen werden kann (exklusiv) flip, clear, rewind setzen Position und Limit flip: Setzt Limit auf aktuelle Position und Position auf 0 clear: Setzt Limit auf Capacity und Position auf 0 rewind: Setzt Position auf 0 flip SYSTEM SOFTWARE 10
Beispiel: Datei kopieren try ( ByteChannel srcchnl = Files.newByteChannel(srcPath, StandardOpenOption.READ); ByteChannel destchnl = Files.newByteChannel(destPath, StandardOpenOption.WRITE); ) { } ByteBuffer buffer = ByteBuffer.allocate(16); int nread = srcchnl.read(buffer); while (nread > 0) { buffer.flip(); destchnl.write(buffer); buffer.clear(); nread = srcchnl.read(buffer); } neuer Buffer Lesen der Daten und Füllen des Buffers flip für Entnehmen der Daten Schreiben der Daten aus Buffer Buffer löschen für neue Daten Lesen neuer Daten SYSTEM SOFTWARE 11
Sockets und Channels Für das Arbeiten mit Channels gibt es spezielle Methoden bei Sockets ServerSocketChannel für Verbindungsaufbau beim Server ServerSocketChannel server = ServerSocketChannel.open(); server.socket().bind(new InetSocketAddress(port)); SocketChannel channel = server.accept(); Öffnen des Channels Binden an Adresse Verbinden mit Clients SocketChannel für Client/Server Kommunikation SocketChannel channel = SocketChannel.open(); channel.connect(new InetSocketAddress(SERVER_IP, PORT)); bidirektionale Kommunikation channel.write( buffer ); channel.read( buffer ); Öffnen des Channels Binden an Adresse Schreiben auf Channel Lesen von Channel Schließen notwendig channel.close(); SYSTEM SOFTWARE 12
Networking Grundlagen Channels und Buffers Nicht-blockierendes Arbeiten mit Selectors Asynchrone Channels Locks SYSTEM SOFTWARE 13
Nicht-blockierende Channel-Operationen (1/2) Channels ermöglichen eine nicht-blockierendes Arbeiten, Operationen werden asynchron ausgeführt Channels müssen in non-blocking Mode gesetzt werden channel.configureblocking(false); Ergebnisse durch Ereignisse gemeldet Selector zum Arbeiten mit Ereignissen Öffnen eines Selectors Selector selector = Selector.open(); Registrierung von Channel-Operationen bei Selector SelectionKey dient dabei als Zugriff auf Registrierung SelectionKey key = channel.register(selector, SelectionKey.OP_READ); SelectionKey.OP_READ SelectionKey.OP_WRITE SelectionKey.OP_OPEN SelectionKey.OP_ACCEPT Mehrere Channels können beim gleichen Selector registriert werden damit kann man durch eine Selector mehrere (viele) Channels bedienen SYSTEM SOFTWARE 14
Nicht-blockierende Channel-Operationen (2/2) Behandlung der Ereignisse Abrufen der Ereignisse vom Selector int n = selector.select(); int n = selector.select(500); Zugriff auf Menge der aufgetretenen Ereignisse Set<SelectionKey> keys = selector.selectedkeys(); Iteration und Behandlung der Ereignisse blockiert bis Ereignisse vorhanden!! mit Timeout in ms Iterator<SelectionKey> keyiterator = keys.iterator(); while (keyiterator.hasnext()) { SelectionKey key = keyiterator.next(); if (key.isreadable()) {... } else if (key.iswritable()) {... }... keyiterator.remove(); remove des Keys notwendig!! } SYSTEM SOFTWARE 15
Beispiel: Horchen auf mehere Sockets Behandlung von Inputs von mehrere Socket-Connections Server erlaubt mehrere Verbindungen aufzubauen ServerSocketChannel server = null; try { server = ServerSocketChannel.open(); server.socket().bind(new InetSocketAddress(port)); server.configureblocking(true); while (!stopserver) { SocketChannel channel = server.accept(); Channel wird in non-blocking Mode versetzt und beim Selector für Read-Operationen registriert channel.configureblocking(false); SelectionKey key = channel.register(selector, SelectionKey.OP_READ); } } catch (IOException e1) {... } finally { try { server.close(); } catch (IOException e) { } } SYSTEM SOFTWARE 16
Beispiel: Horchen auf mehere Sockets Inputs aller Channels können dann in einer Schleife behandelt werden while (! stopserver) { try { int n = selector.select(500); Set<SelectionKey> keys = selector.selectedkeys(); Iterator<SelectionKey> keyit = keys.iterator(); while (keyit.hasnext()) { SelectionKey key = keyit.next(); if (key.isreadable()) { SocketChannel chnl = (SocketChannel)key.channel(); buffer.clear(); chnl.read(buffer); buffer.flip(); byte[] data = new byte[buffer.limit()]; buffer.get(data); System.out.println(Arrays.toString(bytes)); } keyit.remove(); } } catch (IOException e) { } } Reaktion von Inputs Zugriff auf auslösenden Channel Lesen von Channel Ausgabe auf Konsole SYSTEM SOFTWARE 17
Attachments bei SelectionKeys SelectionKey erlaubt Objekt als Attachment mitzuführen kann man gut für benötigte Informationen zur Behandlung des Ereignisses verwenden Anfügen von Attachment bei Registrierung Beachte: Behandlung von unterschiedlichen Channels Object attachment =... ; SelectionKey key = channel.register(selector, SelectionKey.OP_READ); key.attach( attachment ); Abrufen des Attachment beim Auftreten des Ereignisse int n = selector.select(500); Set<SelectionKey> keys = selector.selectedkeys(); Iterator<SelectionKey> keyit = keys.iterator(); while (keyit.hasnext()) { SelectionKey key = keyit.next(); Object attachment = key.attachment(); Beachte: Channel, bei dem Ereignis aufgetreten ist, durch key.channel() SocketChannel chnl = (SocketChannel)key.channel(); SYSTEM SOFTWARE 18
Networking Grundlagen Channels und Buffers Nicht-blockierendes Arbeiten mit Selectors Asynchrone Channels Locks SYSTEM SOFTWARE 19
Asynchrone Channel Asynchrone Channels unterstützen asynchrones Arbeiten entweder unter Verwendung von Futures oder mit CompletionHandler Vorgehen: Öffnen eines AynchronousChannels, z.b. AsynchronousFileChannel AsynchronousFileChannel filechannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ); Asynchrones Lesen mit Verwendung von Future Future<Integer> future = filechannel.read(buffer, 0); Abholen des Ergebnisses blockiert! int nread = future.get(); // Verarbeitung der Daten buffer.flip(); byte[] data = new byte[buffer.limit()]; buffer.get(data); analog AsynchronousSocketChannel, AsynchronousServerSocketChannel SYSTEM SOFTWARE 20
CompletionHandler Mit CompletionHandler kann Callback realisiert werden CompletionHandler bei Operation mitgegeben Nach Ausführung der Operation wird Methode completed oder failed aufgerufen Über attachment kann von Aufruf zur Behandlung ein Objekt durchgereicht werden CompletionHandler generisch bezüglich Resultat- und Attachment-Objekt filechannel.read(buffer, position, attachment, new CompletionHandler<Integer, Object>() { Attachment-Objekt @Override public void completed(integer result, Object attachment) { buffer.flip(); byte[] data = new byte[buffer.limit()]; buffer.get(data); } @Override public void failed(throwable exc, Object attachment) { // handle failed read operation } }); SYSTEM SOFTWARE 21
Networking Grundlagen Channels und Buffers Nicht-blockierendes Arbeiten mit Selectors Asynchrone Channels Locks SYSTEM SOFTWARE 22
Locks Locking von Dateien über Channels FileLock lock = filechannel.lock( ); FileLock lock = filechannel.trylock( ); blockiert liefert null Lock-Objekt für Freigeben des Locks lock.release(); SYSTEM SOFTWARE 23