Java NIO (E/S non bloquantes) avec exemple serveur-client – java.nio.ByteBuffer et channels.Selector – Java NIO Vs. IO
Publié: 2021-08-06
Java NIO
est mon sujet préféré. Je travaille avec NIO depuis 2 ans et j'aimerais partager un Server-Client code
simple pour mes lecteurs qui sont libres d'utiliser ce code dans leur environnement de production.
À partir de JDK 1.4, NIO a été créé pour permettre à tous les programmeurs Java d'implémenter des entrées/sorties très rapides sans avoir à gérer de code natif personnalisé. NIO utilise la bibliothèque java.nio.buffer
comparée à de simples E/S qui drainent et remplissent le tampon en interne de tout système d'exploitation.
Dans ce didacticiel, nous allons passer en revue les bibliothèques java.nio.channels
et java.nio.channels.Selector
.
-
channels
représentent des connexions à des entités capables d'effectuer des opérations d'E/S, telles que des fichiers et des sockets ; définit les sélecteurs , pour les opérations d'E/S multiplexées et non bloquantes. -
selector
peut être créé en invoquant laopen method
de cette classe, qui utilisera le fournisseur de sélecteurs par défaut du système pour créer un nouveau sélecteur.

Si vous avez des below questions
-dessous, vous êtes au bon endroit :
- Comment démarrer avec Java NIO
- Qu'est-ce que Java NIO et les tutoriels Java NIO
- Java NIO asynchrone
- Quelle est l'utilisation exacte du package java nio
- Tutoriel Java NIO
- Comment implémenter des E/S hautes performances avec Java NIO
Commençons:
Étape 1
- Créez
CrunchifyNIOServer.java
qui ouvre la connexion sur leport 1111
- utilisez
isAcceptable()
pour vérifier si le canal est prêt à accepter une nouvelle connexion socket- Si oui - connectez-le
- utilisez
isReadable()
pour vérifier si le canal est prêt pour la lecture- si oui - lire à partir du tampon et imprimer sur la console Eclipse
- Une fois que vous obtenez le nom de l'entreprise "crunchify"
- fermer la connexion
Étape 2
- Créez
CrunchifyNIOClient.java
qui tente de se connecter au serveur sur leport 1111
- Créer une ArrayList avec 5 noms d'entreprise
- Parcourez ArrayList et envoyez chaque companyName au serveur
- Fermer la connexion après la fin de la tâche
Jetez un oeil à ce code Java :
Code serveur – 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 ) ; } } |
Code client – 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 ) ; } } |
Résultat côté serveur :
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 . . . |
Résultat côté client :
1 2 3 4 5 6 |
Connecting to Server on port 1111... sending : Facebook sending : Twitter sending : IBM sending : Google sending : Crunchify |
Quelques FAQ :
- À partir du client, comment puis-je maintenir une connexion persistante ?
- Vous pouvez utiliser
socket.setKeepAlive(true);
pour avoir des connexions actives du côté client.
- Vous pouvez utiliser
- Comment puis-je lire une réponse au message que j'envoie au serveur. Le serveur continue de générer des messages toutes les 10 secondes. J'ai juste besoin de lire la réponse à ma demande. D'après ce que j'ai compris, TCP "transmet" les données au lieu de la fin de l'enregistrement, etc.
- Pour la communication client-serveur, un protocole doit être bien défini. L'appel
readLine()
sera bloqué jusqu'à ce que toutes les données soient renvoyées, ne l'utilisez donc pas.Try reading bytes from the stream until -1 is returned.
- Pour la communication client-serveur, un protocole doit être bien défini. L'appel
Faites-moi savoir si cela fonctionne.
