Ticker

6/recent/ticker-posts

Ad Code

Responsive Advertisement

Java NIO (Non-blocking I/O) with Server-Client Example – java.nio.ByteBuffer and channels.Selector – Java NIO Vs. IO

Java NIO (Non-blocking I:O) with Server-Client Example - CrunchifyNIOServer.java

Java NIO is my favorite topic. I have been working with NIO since last 2 years and would like to share simple Server-Client code for my readers who are free to use this code in their production environment.

Starting JDK 1.4, NIO was created to allow all Java programmers to implement very high-speed input/output without having to deal with custom native code. NIO uses java.nio.buffer library compare to simple I/O which drains and fills back buffer internally any operating system.

In this tutorial we will go over java.nio.channels and java.nio.channels.Selector libraries.

  • channels represent connections to entities that are capable of performing I/O operations, such as files and sockets; defines selectors, for multiplexed, non-blocking I/O operations.
  • 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.
java.nio package explanation with API details

If you have below questions then you are at right place:

  • How to get started with Java NIO
  • What is Java NIO and Java NIO tutorials
  • Asynchronous Java NIO
  • What is the exact use of java nio package
  • Java NIO Tutorial
  • How to implement High-Performance I/O with Java NIO

Let’s get started:

Step-1

  • Create CrunchifyNIOServer.java which opens connection on port 1111
  • use isAcceptable() to check if channel is ready to accept a new socket connection
    • If yes – connect it
  • use isReadable() to check if channel is ready for reading
    • if yes – read from buffer and print on Eclipse console
  • Once you get last company name “crunchify”

Step-2

  • Create CrunchifyNIOClient.java which tries to connect to server on port 1111
  • Create ArrayList with 5 company names
  • Iterate through ArrayList and send each companyName to server
  • Close connection after task finish

Take a look at this Java Code:

Server Code – CrunchifyNIOServer.java

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

Java NIO (Non-blocking I:O) with Server-Client Example - CrunchifyNIOClient.java
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);
        }
}

Result at Server Side:

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...

Result at Client Side:

Connecting to Server on port 1111...
sending: Facebook
sending: Twitter
sending: IBM
sending: Google
sending: Crunchify

Few FAQs:

  1. From the client, how do I maintain a persistent connection?
    • You could use socket.setKeepAlive(true); to have connections alive from client side.
  2. How do I read a response to the message I send to the server. The server keeps generating messages every 10 sec. I just need to read response to my request. From what I understand, TCP “streams” data instead of end of record, etc.
    • For client server communication, a protocol needs to be well defined. readLine() call will be blocked until all data will be returned, so don’t use it. Try reading bytes from the stream until -1 is returned.

Let me know if that works.

The post Java NIO (Non-blocking I/O) with Server-Client Example – java.nio.ByteBuffer and channels.Selector – Java NIO Vs. IO appeared first on Crunchify.

Enregistrer un commentaire

0 Commentaires