Java NIO (Non-blocking I/O) mit Server-Client-Beispiel – java.nio.ByteBuffer und channels.Selector – Java NIO Vs. IO
Veröffentlicht: 2021-08-06
Java NIO
ist mein Lieblingsthema. Ich arbeite seit den letzten 2 Jahren mit NIO und würde gerne einfachen Server-Client code
für meine Leser freigeben, die diesen Code in ihrer Produktionsumgebung verwenden können.
Ab JDK 1.4 wurde NIO entwickelt, um allen Java-Programmierern die Implementierung von Eingabe/Ausgabe mit sehr hoher Geschwindigkeit zu ermöglichen, ohne sich mit benutzerdefiniertem nativen Code befassen zu müssen. NIO verwendet die java.nio.buffer
Bibliothek im Vergleich zu einfachen E/A-Vorgängen, die den Puffer intern in jedem Betriebssystem leeren und auffüllen.
In diesem Tutorial gehen wir auf die Bibliotheken java.nio.channels
und java.nio.channels.Selector
.
-
channels
stellen Verbindungen zu Entitäten dar, die E/A-Operationen ausführen können, wie Dateien und Sockets; definiert Selektoren für gemultiplexte, nicht blockierende E/A-Operationen. -
selector
kann durch Aufrufen deropen method
dieser Klasse erstellt werden, die den standardmäßigen Selektoranbieter des Systems verwendet, um einen neuen Selektor zu erstellen.

Wenn Sie folgende below questions
haben, dann sind Sie hier richtig:
- Erste Schritte mit Java NIO
- Was ist Java NIO und Java NIO-Tutorials
- Asynchrones Java-NIO
- Was ist die genaue Verwendung des Java Nio-Pakets
- Java-NIO-Tutorial
- So implementieren Sie High-Performance I/O mit Java NIO
Lass uns anfangen:
Schritt 1
- Erstellen Sie
CrunchifyNIOServer.java
, das die Verbindung aufport 1111
öffnet - Verwenden
isAcceptable()
, um zu prüfen, ob der Kanal bereit ist, eine neue Socket-Verbindung zu akzeptieren- Wenn ja – anschließen
- Verwenden
isReadable()
, um zu prüfen, ob der Kanal zum Lesen bereit ist- wenn ja – aus dem Puffer lesen und auf der Eclipse-Konsole drucken
- Sobald Sie den letzten Firmennamen erhalten, „crunchify“
- Verbindung schließen
Schritt 2
- Erstellen Sie
CrunchifyNIOClient.java
, das versucht, eine Verbindung zum Server aufport 1111
herzustellen - Erstellen Sie eine ArrayList mit 5 Firmennamen
- Durchlaufen Sie ArrayList und senden Sie jeden Firmennamen an den Server
- Verbindung nach Abschluss der Aufgabe schließen
Schauen Sie sich diesen Java-Code an:
Servercode – CrunchifyNIOServer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
package crunchify . com . tutorials ; import java . io . IOException ; import java . net . InetSocketAddress ; import java . nio . ByteBuffer ; import java . nio . channels . SelectionKey ; import java . nio . channels . Selector ; import java . nio . channels . ServerSocketChannel ; import java . nio . channels . SocketChannel ; import java . util . Iterator ; import java . util . Set ; /** * @author Crunchify.com * Java NIO (Non-blocking I/O) with Server-Client Example - java.nio.ByteBuffer and channels.Selector * This is CrunchifyNIOServer.java */ public class CrunchifyNIOServer { @ SuppressWarnings ( "unused" ) public static void main ( String [ ] args ) throws IOException { // Selector: A multiplexor of SelectableChannel objects. // A selector may be created by invoking the open method of this class, which will use the system's default selector provider to create a new selector. // A selector may also be created by invoking the openSelector method of a custom selector provider. A selector remains open until it is closed via its close method. Selector selector = Selector . open ( ) ; // selector is open here // ServerSocketChannel: A selectable channel for stream-oriented listening sockets. // A server-socket channel is created by invoking the open method of this class. // It is not possible to create a channel for an arbitrary, pre-existing ServerSocket. ServerSocketChannel crunchifySocket = ServerSocketChannel . open ( ) ; // InetSocketAddress: This class implements an IP Socket Address (IP address + port number) It can also be a pair (hostname + port number), // in which case an attempt will be made to resolve the hostname. // If resolution fails then the address is said to be unresolved but can still be used on some circumstances like connecting through a proxy. InetSocketAddress crunchifyAddr = new InetSocketAddress ( "localhost" , 1111 ) ; // Binds the channel's socket to a local address and configures the socket to listen for connections crunchifySocket . bind ( crunchifyAddr ) ; // Adjusts this channel's blocking mode. crunchifySocket . configureBlocking ( false ) ; int ops = crunchifySocket . validOps ( ) ; // SelectionKey: A token representing the registration of a SelectableChannel with a Selector. // A selection key is created each time a channel is registered with a selector. // A key remains valid until it is cancelled by invoking its cancel method, by closing its channel, or by closing its selector. SelectionKey selectKy = crunchifySocket . register ( selector , ops , null ) ; // Infinite loop.. // Keep server running while ( true ) { log ( "I'm a server and I'm waiting for new connection and buffer select..." ) ; // Selects a set of keys whose corresponding channels are ready for I/O operations selector . select ( ) ; // token representing the registration of a SelectableChannel with a Selector Set < SelectionKey > crunchifyKeys = selector . selectedKeys ( ) ; Iterator < SelectionKey > crunchifyIterator = crunchifyKeys . iterator ( ) ; while ( crunchifyIterator . hasNext ( ) ) { SelectionKey myKey = crunchifyIterator . next ( ) ; // Tests whether this key's channel is ready to accept a new socket connection if ( myKey . isAcceptable ( ) ) { SocketChannel crunchifyClient = crunchifySocket . accept ( ) ; // Adjusts this channel's blocking mode to false crunchifyClient . configureBlocking ( false ) ; // Operation-set bit for read operations crunchifyClient . register ( selector , SelectionKey . OP_READ ) ; log ( "Connection Accepted: " + crunchifyClient . getLocalAddress ( ) + "\n" ) ; // Tests whether this key's channel is ready for reading } else if ( myKey . isReadable ( ) ) { SocketChannel crunchifyClient = ( SocketChannel ) myKey . channel ( ) ; // ByteBuffer: A byte buffer. // This class defines six categories of operations upon byte buffers: // Absolute and relative get and put methods that read and write single bytes; // Absolute and relative bulk get methods that transfer contiguous sequences of bytes from this buffer into an array; ByteBuffer crunchifyBuffer = ByteBuffer . allocate ( 256 ) ; crunchifyClient . read ( crunchifyBuffer ) ; String result = new String ( crunchifyBuffer . array ( ) ) . trim ( ) ; log ( "Message received: " + result ) ; if ( result . equals ( "Crunchify.com" ) ) { crunchifyClient . close ( ) ; log ( "\nIt's time to close connection as we got last company name 'Crunchify'" ) ; log ( "\nServer will keep running. Try running client again to establish new connection" ) ; } } crunchifyIterator . remove ( ) ; } } } private static void log ( String str ) { System . out . println ( str ) ; } } |
Client-Code – CrunchifyNIOClient.java

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
package crunchify . com . tutorials ; import java . io . IOException ; import java . net . InetSocketAddress ; import java . nio . ByteBuffer ; import java . nio . channels . SocketChannel ; import java . util . ArrayList ; /** * @author Crunchify.com * Java NIO (Non-blocking I/O) with Server-Client Example - java.nio.ByteBuffer and channels.Selector * This is CrunchifyNIOClient.java */ public class CrunchifyNIOClient { public static void main ( String [ ] args ) throws IOException , InterruptedException { InetSocketAddress crunchifyAddr = new InetSocketAddress ( "localhost" , 1111 ) ; // selectable channel for stream-oriented connecting sockets SocketChannel crunchifyClient = SocketChannel . open ( crunchifyAddr ) ; log ( "Connecting to Server on port 1111..." ) ; ArrayList <String> companyDetails = new ArrayList <String> ( ) ; // create a ArrayList with companyName list companyDetails . add ( "Facebook" ) ; companyDetails . add ( "Twitter" ) ; companyDetails . add ( "IBM" ) ; companyDetails . add ( "Google" ) ; companyDetails . add ( "Crunchify" ) ; for ( String companyName : companyDetails ) { byte [ ] message = new String ( companyName ) . getBytes ( ) ; ByteBuffer buffer = ByteBuffer . wrap ( message ) ; crunchifyClient . write ( buffer ) ; log ( "sending: " + companyName ) ; buffer . clear ( ) ; // wait for 2 seconds before sending next message Thread . sleep ( 2000 ) ; } // close(): Closes this channel. // If the channel has already been closed then this method returns immediately. // Otherwise it marks the channel as closed and then invokes the implCloseChannel method in order to complete the close operation. crunchifyClient . close ( ) ; } private static void log ( String str ) { System . out . println ( str ) ; } } |
Ergebnis auf Serverseite:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
I 'm a server and I' m waiting for new connection and buffer select . . . Connection Accepted : / 127.0.0.1 : 1111 I 'm a server and <meta charset="utf-8"/>I' m waiting for new connection and buffer select . . . Message received : Facebook < meta charset = "utf-8" / > I 'm a server and <meta charset="utf-8"/>I' m waiting for new connection and buffer select . . . Message received : Twitter < meta charset = "utf-8" / > I 'm a server and <meta charset="utf-8"/>I' m waiting for new connection and buffer select . . . Message received : IBM < meta charset = "utf-8" / > I 'm a server and <meta charset="utf-8"/>I' m waiting for new connection and < a href = "https://crunchify.com/how-to-remove-duplicate-elements-from-csv-or-any-other-file-in-java/" target = "_blank" rel = "noreferrer noopener" > buffer < / a > select . . . Message received : Google < meta charset = "utf-8" / > I 'm a server and <meta charset="utf-8"/>I' m waiting for new connection and buffer select . . . Message received : Crunchify It 's time to <a href="https://crunchify.com/json-manipulation-in-java-examples/" target="_blank" rel="noreferrer noopener">close connection</a> as we got last company name ' Crunchify ' Server will keep running. Try running client again to establish new connection <meta charset="utf-8"/>I' m a server and < meta charset = "utf-8" / > I ' m waiting for new connection and buffer select . . . |
Ergebnis auf Clientseite:
1 2 3 4 5 6 |
Connecting to Server on port 1111... sending : Facebook sending : Twitter sending : IBM sending : Google sending : Crunchify |
Einige häufig gestellte Fragen:
- Wie halte ich vom Client aus eine dauerhafte Verbindung aufrecht?
- Sie könnten
socket.setKeepAlive(true);
um Verbindungen von der Clientseite am Leben zu haben.
- Sie könnten
- Wie lese ich eine Antwort auf die Nachricht, die ich an den Server sende? Der Server generiert weiterhin alle 10 Sekunden Nachrichten. Ich muss nur die Antwort auf meine Anfrage lesen. Soweit ich weiß, "streamt" TCP Daten anstelle des Datensatzendes usw.
- Für die Client-Server-Kommunikation muss ein Protokoll gut definiert sein.
readLine()
Aufruf wird blockiert, bis alle Daten zurückgegeben wurden, verwenden Sie ihn also nicht.Try reading bytes from the stream until -1 is returned.
- Für die Client-Server-Kommunikation muss ein Protokoll gut definiert sein.
Lass mich wissen, ob das funktioniert.
