1. Einführung in die NIO -Bibliothek
1. Pufferpuffer
Ein Puffer ist ein Objekt, das einige Daten enthält, die geschrieben und vorgelesen werden sollen.
In NIO werden alle Daten in einem Puffer verarbeitet. Beim Lesen von Daten wird es direkt vom Kanal zum Puffer gelesen und beim Schreiben von Daten auch vom Puffer in den Kanal geschrieben.
Ein Puffer ist im Wesentlichen ein Array, normalerweise ein Byte -Array (ByteBuffer) oder andere Arten von Arrays. Darüber hinaus enthält der Puffer Informationen wie strukturierten Zugriff auf Daten und die Wartung von Lese- und Schreiborten.
Die Vererbungsbeziehung der Pufferklasse ist in der folgenden Abbildung dargestellt:
2. Kanal
Channel ist ein Kanal, in dem Netzwerkdaten über den Kanal gelesen und geschrieben werden. Der Unterschied zwischen einem Kanal und einem Stream besteht darin, dass der Kanal bidirektional ist (mit dem Kanal kann dieser gleichzeitig das Lesen und Schreiben verwendet werden) und der Stream bewegt sich nur in eine Richtung.
Kanäle können grob in zwei Kategorien unterteilt werden: SelectableChannel für das Lesen und Schreiben von Netzwerk (ServerSocketchannel und Socketchannel sind ihre Unterklassen) und FileChannel für Dateioperationen.
Das folgende Beispiel zeigt die Datei mithilfe von Filechannel an, um Daten in eine Datei zu schreiben, Daten aus einer Datei zu lesen und die Dateidaten in eine andere Datei zu kopieren:
public class niotest {public static void main (String [] args) löst ioException {copyFile () aus; } // Die Datei private statische void copyFile () {FileInputStream in = null; FileOutputStream out = null; try {in = new FileInputStream ("src/main/java/data/in-data.txt"); out = new FileOutputStream ("src/main/java/data/out-data.txt"); Filechannel inchannel = in.getchannel (); Filechannel outchannel = out.getCannel (); Bytebuffer buffer = bytebuffer.alcode (1024); int bytesRead = inchannel.read (puffer); while (byteSread! =-1) {buffer.flip (); Outchannel.Write (Puffer); buffer.clear (); byteSread = inchannel.read (puffer); }} catch (FilenotFoundException e) {// todo automatisch generiertes Catch-Block e.printstacktrace (); } catch (ioException e) {// Todo automatisch generierter Catch-Block e.printstacktrace (); }} // Datei private statische void write filenio () {try {randomAccessfile fout = new randomAccessfile ("src/main/java/data/nio-data.txt", "rw"); Filechannel fc = fout.getchannel (); Bytebuffer buffer = bytebuffer.alcode (1024); Buffer.put ("Hi123" .GetByTes ()); puffer.flip (); try {fc.write (puffer); } catch (ioException e) {// Todo automatisch generierter Catch-Block e.printstacktrace (); }} catch (FilenotFoundException e) {// todo automatisch generiertes Catch-Block e.printstacktrace (); }} // Datei private statische void ReadFilenio () {FileInputStream FileInputStream; try {fileInputStream = new FileInputStream ("src/main/java/data/nio-data.txt"); Filechannel filechannel = fileInputStream.getchannel (); // Kanal aus fileInputStream bytebuffer bytebuffer = bytebuffer.Allecode (1024); // Erstellen Sie einen Puffer int int bytesread = filechannel.read (bytebuffer); // die Daten zu dem Bytesread (Bytesread! */ bytebuffer.flip (); // HasRemaining (): Informieren Sie, ob es ein Element zwischen der aktuellen Position und der Grenze gibt (bytebuffer.hasremaining ()) {System.out.print ((char) bytebuffer.get ()); } /** Löschen Sie den Puffer* Position = 0; * Limit = Kapazität; */ bytebuffer.clear (); byteRead = filechannel.read (bytebuffer); }} catch (FilenotFoundException e) {// todo automatisch generiertes Catch-Block e.printstacktrace (); } catch (ioException e) {// Todo automatisch generierter Catch-Block e.printstacktrace (); }}}3. Multiplexer -Selektor
Der Multiplexer bietet die Möglichkeit, auf Aufgaben auszuwählen, die bereit sind. Der Selektor wird den darauf registrierten Kanal ständig abfragen. Wenn ein Kanal ein Lese- oder Schreibereignis sendet, befindet sich der Kanal im Ready -Status und wird vom Selektor befragt. Anschließend kann der Satz Bereitschaftskanäle über den SelectionKey erhalten werden, um nachfolgende E/A -Operationen auszuführen.
Ein Multiplexer -Selektor kann mehrere Kanäle gleichzeitig befragen. Da JDK EPOLL anstelle der herkömmlichen Auswahlimplementierung verwendet, hat es nicht die Grenze des maximalen Verbindungsgriffs 1024/2048, was bedeutet, dass nur ein Thread für die Umfrage des Selektors verantwortlich sein und auf Tausende von Clients zugreifen kann. Das Modell ist in der folgenden Abbildung dargestellt:
Verarbeiten Sie einen Selektor mit einem einzelnen Thread. Um den Selektor zu verwenden, müssen Sie den Kanal mit Selektor registrieren und dann seine Select () -Methode aufrufen. Diese Methode blockiert, bis ein registrierter Kanal Event bereit ist. Sobald diese Methode zurückgegeben ist, kann der Thread diese Ereignisse verarbeiten, z. B. neue Verbindungen, Datenempfang usw.
Notiz:
1. Welches Auswahlmodell?
SELECT ist ein Ereignisauslösermechanismus, der die Verarbeitung nach dem Wartenereignis auslöst und hauptsächlich für die Verarbeitung des Clients durch die Linux -Implementierung von Servern verwendet wird.
Es kann gleichzeitig eine Reihe von nicht blockierenden IO-Geräten erkennen, die nicht blockierende, unabhängig davon, ob es Ereignisse gibt (z. B. lesbare, beschreibbare, hohe Prioritätsfehlerausgabe usw.), bis ein Gerät ein Ereignis auslöst oder die angegebene Wartezeit überschreitet. Das heißt, ihre Verantwortung ist nicht, IO zu tun, sondern dem Anrufer zu helfen, das aktuell bereite Gerät zu finden.
2. Was ist das Epoll -Modell?
Die Entwurfsidee von EPOLD besteht darin, den einzelnen Betrieb von Select/Poll in 1 EPOLL_CREATE + Multiple EPOLL_Ctrl + One Warted zu teilen. Darüber hinaus hat der Kernel ein Dateisystem "eventPollfs" für Epolloperationen hinzugefügt. Jede oder mehr zu überwachende Dateideskriptoren haben einen Inode -Knoten des entsprechenden Ereignispollfs -Dateisystems, und die Hauptinformationen werden in der EventPoll -Struktur gespeichert. Die wichtigen Informationen der überwachten Dateien werden in der Epitemstruktur gespeichert. Sie sind also eine Eins-zu-Viele-Beziehung.
2. NIO Server-Side-Entwicklung
Funktionsbeschreibung: Schalten Sie die Serverseite ein und senden Sie den Hello String an jeden Access -Client.
Es gibt mehrere Hauptschritte für die Verwendung von NIO für die serverseitige Entwicklung:
1. Erstellen Sie ServerSocketchannel und konfigurieren Sie es im nicht blockierenden Modus
ServerSocketchannel = ServerSocketchannel.open (); ServerSocketchannel.ConfigureBlocking (falsch);
2. Binden Sie das Hören und Konfigurieren von TCP -Parametern wie der Rückstandgröße
ServerSocketchannel.Socket (). Bind (New InetSocketaddress (8080));
3. Erstellen Sie einen unabhängigen E/A -Thread, um den Multiplexer -Selektor zu befragen
4. Erstellen Sie einen Auswahl-
selector = selector.open (); ServerSocketchannel.register (Selector, SelectionKey.op_accept);
5. Starten Sie den E/A -Thread, führen Sie die Methode aus selector.select () im Schleifenkörper aus und befragen
Während (true) {try {// select () Blöcke, bis mindestens ein Kanal auf dem Ereignis bereit ist, das Sie registriert haben //, wenn kein Kanal fertig ist, blockiert er hier // SELECT (Langzeitübergreifend) ist der gleiche wie select (), außer dass es Timeout Milliseconds (Parameter) blockiert. Selector.Select (); } catch (ioException e) {// Todo automatisch generierter Catch-Block e.printstacktrace (); brechen; }}6. Bei der Wahl des Kanals im bereiten Zustand muss er beurteilt werden. Wenn es sich um den Status von OP_accept handelt, bedeutet dies, dass es sich um einen neuen Client -Zugriff handelt. Rufen Sie dann ServerSocketchannel.accept () -Methode an, um den neuen Client zu akzeptieren.
// RETTIEREN SIE DEN FEEFORTE SELECTIONKEY und dann iterieren, um set <SelectionKey> Readkeys = selector.selectedKeys () auszuführen; für (iterator <SelectionKey> it = readKeys.Iderator (); it.hasnext ();) {SelectionKey key = it.Next (); it.remove (); try {if (key.isacceptable ()) {serverSocketchannel server = (serversSocketchannel) key.channel (); Socketchannel client = server.accept (); Client.ConfigureBlocking (falsch); client.register (selector, selectionKey.op_write); } else if (key.iswrible ()) {socketchannel client = (socketchannel) key.channel (); Bytebuffer buffer = bytebuffer.alcode (20); String str = "Hallo"; buffer = bytebuffer.wrap (str.getBytes ()); Client.Write (Puffer); key.cancel (); }} catch (ioException e) {e.printstacktrace (); key.cancel (); try {key.channel (). close (); } catch (ioException e1) {// Todo automatisch generiertes Catch-Block e1.printstacktrace (); }}}7. Legen Sie den neu zugegriffenen Client-Link-SocketAntel auf den nicht blockierenden Modus fest und konfigurieren Sie einige andere TCP-Parameter.
if (key.isacceptable ()) {ServerSocketchannel Server = (ServerSocketchannel) key.channel (); Socketchannel client = server.accept (); Client.ConfigureBlocking (falsch); ...}8. Registrieren Sie Socketchannel an Selektor und hören Sie sich Op_write an
client.register (selector, selectionKey.op_write);
9. Wenn der befragte Kanal op_write ist, bedeutet dies, dass Daten in die Sockchannel geschrieben werden sollen, das ByteBuffer -Objekt konstruiert und das Datenpaket geschrieben wird.
sonst if (key.iswrible ()) {Socketchannel client = (socketchannel) key.channel (); Bytebuffer buffer = bytebuffer.alcode (20); String str = "Hallo"; buffer = bytebuffer.wrap (str.getBytes ()); Client.Write (Puffer); key.cancel (); }Der vollständige Code lautet wie folgt:
Import Java.io.ioException; Import Java.net.inetsocketaddress; Import Java.nio.ByTebuffer; Import Java.nio.Channels.SelectionKey; Import Java.nio.Channels.Seselector; java.nio.channels.socketchannel; import Java.util.iterator; import Java.util.set; öffentliche Klasse ServerSocketAndemo {public static void main (String [] args) {ServerSocketAntel ServersSocketAntel; ServersSocketchannel.open (); ServerSocketchannel.ConfigureBlocking (False); ServerSocketchannel.Socket (). Bind (new InetSocketadDress (8080)); selector = selector.open (); Serversocketchannel.register (Selector, SelectorKector.Op.Op.Op.AcCapection; blocke.printstacktrace ();} while (true) {try {// select () Blöcke, bis mindestens ein Kanal auf dem Ereignis fertig ist, das Sie registriert haben // Wenn kein Kanal fertig ist, blockiert es hier die ganze Zeit. selector.select ();} catch (ioException e) {// todo automatisch generiert blocke.printstacktrace (); break;} // RETATION DIE FEEFENSETZIGE SELECTIONKEY und dann iterate, um set <selectionKey> readke = selector.selectortedkeys (); {SelectionKey key = it.next (); it.remove (); try {if (key.isacceptable ()) {serverSocketchannel server = (serversSocketchannel). if (key.iswrible ()) {Socketchannel client = (socketchannel) key.channel (); {e.printStackTrace();key.cancel();try {key.channel().close();}catch (IOException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}}}}}}}}}}}Wir verwenden Telnet Localhost 8080, um mehrere Clients zu simulieren:
Die Programme für Programmläufe sind wie folgt:
Zusammenfassen
Das obige ist die detaillierte Erklärung der Java Nio-Server-Seite-Entwicklung in diesem Artikel. Ich hoffe, dass es für alle hilfreich sein wird. Interessierte Freunde können weiterhin auf andere verwandte Themen auf dieser Website verweisen. Wenn es Mängel gibt, hinterlassen Sie bitte eine Nachricht, um darauf hinzuweisen. Vielen Dank an Freunde für Ihre Unterstützung für diese Seite!