상세 컨텐츠

본문 제목

자바 네트워크 NIO 예제 관련

프로그래밍 관련/네트워크, 통신

by AlrepondTech 2016. 5. 17. 17:09

본문

반응형



/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



출처: http://crunchify.com/java-nio-non-blocking-io-with-server-client-example-java-nio-bytebuffer-and-channels-selector-java-nio-vs-io/




Java NIO client server example with Selector and Channels

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”
    • close connection

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

Client Code – CrunchifyNIOClient.java

Result at Server Side:

Result at Client Side:

Have a suggestion or anything to add to this article? Chime in and share as a comment OR post it inforum.



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



출처: https://examples.javacodegeeks.com/core-java/nio/java-nio-socket-example/



This article introduces the SocketChannel class and its basic usage. This class is defined in the java.nio package.

1. Standard Java sockets

Socket programming involves two systems communicating with one another. In implementations prior to NIO, Java TCP client socket code is handled by the java.net.Socket class. A socket is one end-point of a two-way communication link between two programs running on the network. Socket classes are used to represent the connection between a client program and a server program. The java.net package provides two classes,Socket and ServerSocket, that implement the client side of the connection and the server side of the connection, respectively. The below image illustrates the nature of this communication:


A socket is basically a blocking input/output device. It makes the thread that is using it to block on reads and potentially also block on writes if the underlying buffer is full. Therefore, different threads are required if the server has many open sockets. From a simplistic perspective, the process of a blocking socket communication is as follows:

  • Create a ServerSocket, specifying a port to listen on.
  • Invoke the ServerSocket’s accept() method to listen on the configured port for a client connection.
  • When a client connects to the server, the accept() method returns a Socket through which the server can communicate with the client: an InputStream is obtained to read from the client and an OutputStream to write to the client.

2. Nonblocking SocketChannel with java.nio

With the standard java sockets, if the server needed to be scalable, the socket had to be passed to another thread for processing so that the server could continue listening for additional connections, meaning call the ServerSocket’s accept()method again to listen for another connection.

SocketChannel on the other hand is a non-blocking way to read from sockets, so that you can have one thread communicate with multiple open connections at once. With socket channel we describe the communication channel between client and server. It is identified by the server IP address and the port number. Data passes through the socket channel by buffer items. A selector monitors the recorded socket channels and serializes the requests, which the server has to satisfy. The Keys describe the objects used by the selector to sort the requests. Each key represents a single client sub-request and contains information to identify the client and the type of the request. With non-blocking I/O, someone can program networked applications to handle multiple simultaneous connections without having to manage multiple thread collection, while also taking advantage of the new server scalability that is built in to java.nio. The below image illustrates this procedure:


3. Example

The following example shows the use of SocketChannel for creating a simple echo server, meaning it echoes back any message it receives.

3.1. The Server code

001import java.io.IOException;
002import java.net.InetSocketAddress;
003import java.net.Socket;
004import java.net.SocketAddress;
005import java.nio.ByteBuffer;
006import java.nio.channels.SelectionKey;
007import java.nio.channels.Selector;
008import java.nio.channels.ServerSocketChannel;
009import java.nio.channels.SocketChannel;
010import java.util.*;
011 
012public class SocketServerExample {
013    private Selector selector;
014    private Map<SocketChannel,List> dataMapper;
015    private InetSocketAddress listenAddress;
016     
017    public static void main(String[] args) throws Exception {
018        Runnable server = new Runnable() {
019            @Override
020            public void run() {
021                 try {
022                    new SocketServerExample("localhost"8090).startServer();
023                catch (IOException e) {
024                    e.printStackTrace();
025                }
026                 
027            }
028        };
029         
030        Runnable client = new Runnable() {
031            @Override
032            public void run() {
033                 try {
034                     new SocketClientExample().startClient();
035                catch (IOException e) {
036                    e.printStackTrace();
037                catch (InterruptedException e) {
038                    e.printStackTrace();
039                }
040                 
041            }
042        };
043       new Thread(server).start();
044       new Thread(client, "client-A").start();
045       new Thread(client, "client-B").start();
046    }
047 
048    public SocketServerExample(String address, int port) throws IOException {
049        listenAddress = new InetSocketAddress(address, port);
050        dataMapper = new HashMap<SocketChannel,List>();
051    }
052 
053    // create server channel   
054    private void startServer() throws IOException {
055        this.selector = Selector.open();
056        ServerSocketChannel serverChannel = ServerSocketChannel.open();
057        serverChannel.configureBlocking(false);
058 
059        // retrieve server socket and bind to port
060        serverChannel.socket().bind(listenAddress);
061        serverChannel.register(this.selector, SelectionKey.OP_ACCEPT);
062 
063        System.out.println("Server started...");
064 
065        while (true) {
066            // wait for events
067            this.selector.select();
068 
069            //work on selected keys
070            Iterator keys = this.selector.selectedKeys().iterator();
071            while (keys.hasNext()) {
072                SelectionKey key = (SelectionKey) keys.next();
073 
074                // this is necessary to prevent the same key from coming up
075                // again the next time around.
076                keys.remove();
077 
078                if (!key.isValid()) {
079                    continue;
080                }
081 
082                if (key.isAcceptable()) {
083                    this.accept(key);
084                }
085                else if (key.isReadable()) {
086                    this.read(key);
087                }
088            }
089        }
090    }
091 
092    //accept a connection made to this channel's socket
093    private void accept(SelectionKey key) throws IOException {
094        ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
095        SocketChannel channel = serverChannel.accept();
096        channel.configureBlocking(false);
097        Socket socket = channel.socket();
098        SocketAddress remoteAddr = socket.getRemoteSocketAddress();
099        System.out.println("Connected to: " + remoteAddr);
100 
101        // register channel with selector for further IO
102        dataMapper.put(channel, new ArrayList());
103        channel.register(this.selector, SelectionKey.OP_READ);
104    }
105     
106    //read from the socket channel
107    private void read(SelectionKey key) throws IOException {
108        SocketChannel channel = (SocketChannel) key.channel();
109        ByteBuffer buffer = ByteBuffer.allocate(1024);
110        int numRead = -1;
111        numRead = channel.read(buffer);
112 
113        if (numRead == -1) {
114            this.dataMapper.remove(channel);
115            Socket socket = channel.socket();
116            SocketAddress remoteAddr = socket.getRemoteSocketAddress();
117            System.out.println("Connection closed by client: " + remoteAddr);
118            channel.close();
119            key.cancel();
120            return;
121        }
122 
123        byte[] data = new byte[numRead];
124        System.arraycopy(buffer.array(), 0, data, 0, numRead);
125        System.out.println("Got: " new String(data));
126    }
127}

From the above code:

  • In the main() method on lines 43-45, one thread for creating the ServerSocketChannel is started and two client threads responsible for starting the clients which will create a SocketChannel for sending messsages to the server.
    1new Thread(server).start();
    2new Thread(client, "client-A").start();
    3new Thread(client, "client-B").start();
  • In the startServer() method on line 54,  the server SocketChannel is created as nonBlocking, the server socket is retrieved and bound to the specified port:
    1ServerSocketChannel serverChannel = ServerSocketChannel.open();
    2serverChannel.configureBlocking(false);
    3// retrieve server socket and bind to port
    4serverChannel.socket().bind(listenAddress);

    Finally, the register method associates the selector to the socket channel.

    1serverChannel.register(this.selector, SelectionKey.OP_ACCEPT);

    The second parameter represents the type of the registration. In this case, we use OP_ACCEPT, which means the selector merely reports that a client attempts a connection to the server. Other possible options are: OP_CONNECT, which will be used by the client; OP_READ; and OP_WRITE.
    After that, the select method is used on line 67, which blocks the execution and waits for events recorded on the selector in an infinite loop.

    1this.selector.select();
  • The selector waits for events and creates the keys. According to the key-types, an opportune operation is performed. There are four possible types for a key:
     

    • Acceptable: the associated client requests a connection.
    • Connectable: the server accepted the connection.
    • Readable: the server can read.
    • Writeable: the server can write.
  • If an acceptable key is found, the accept(SelectionKey key) on line 93 is invoked in order to create a channel which accepts this connection, creates a standard java socket on line 97 and register the channel with the selector:
    1ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
    2SocketChannel channel = serverChannel.accept();
    3channel.configureBlocking(false);
    4Socket socket = channel.socket();
    5SocketAddress remoteAddr = socket.getRemoteSocketAddress();
  • After receiving a readable key from the client, the read(SelectionKey key) is called on line 107 which reads from the socket channel. A byte buffer is allocated for reading from the channel
    1numRead = channel.read(buffer);

    and the client’s transmitted data are echoed on System.out:

    1System.out.println("Got: " new String(data));

3.2. The Client code

01import java.io.IOException;
02import java.net.InetSocketAddress;
03import java.nio.ByteBuffer;
04import java.nio.channels.SocketChannel;
05 
06public class SocketClientExample {
07  
08    public void startClient()
09            throws IOException, InterruptedException {
10  
11        InetSocketAddress hostAddress = new InetSocketAddress("localhost"8090);
12        SocketChannel client = SocketChannel.open(hostAddress);
13  
14        System.out.println("Client... started");
15         
16        String threadName = Thread.currentThread().getName();
17  
18        // Send messages to server
19        String [] messages = new String []
20                {threadName + ": test1",threadName + ": test2",threadName + ": test3"};
21  
22        for (int i = 0; i < messages.length; i++) {
23            byte [] message = new String(messages [i]).getBytes();
24            ByteBuffer buffer = ByteBuffer.wrap(message);
25            client.write(buffer);
26            System.out.println(messages [i]);
27            buffer.clear();
28            Thread.sleep(5000);
29        }
30        client.close();           
31    }
32}
  • In the above client code, each client thread creates a socket channel on the server’s host address on line 12:
    1SocketChannel client = SocketChannel.open(hostAddress);
  • On line 19, a String array is created to be transmitted to the server using the previously created socket. The data contain also each thread’s name for distinguishing the sender:
    1String threadName = Thread.currentThread().getName();
    2// Send messages to server
    3String [] messages = new String []
    4{threadName + ": test1",threadName + ": test2",threadName + ": test3"};
  • For each string message a buffer is created on line 24:
    1ByteBuffer buffer = ByteBuffer.wrap(message);

    and each message is written to the channel from the given buffer on line 25:

    1ByteBuffer buffer = ByteBuffer.wrap(message);

3.3. The output

01Server started...
02Client... started
03Client... started
04client-A: test1
05client-B: test1
06Connected to: /127.0.0.1:51468
07Got: client-B: test1
08Connected to: /127.0.0.1:51467
09Got: client-A: test1
10client-A: test2
11client-B: test2
12Got: client-B: test2
13Got: client-A: test2
14client-A: test3
15client-B: test3
16Got: client-B: test3
17Got: client-A: test3
18Connection closed by client: /127.0.0.1:51468
19Connection closed by client: /127.0.0.1:51467

4. Download Java Source Code

This was an example of java.nio.SocketChannel

Download
You can download the full source code of this example here: SocketExampleNio.zip

SocketExampleNio.zip


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



출처: https://gist.github.com/Botffy/3860641


simple Java NIO chat server
package niochat;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.io.IOException;
import java.util.*;
public class NiochatServer implements Runnable {
private final int port;
private ServerSocketChannel ssc;
private Selector selector;
private ByteBuffer buf = ByteBuffer.allocate(256);
NiochatServer(int port) throws IOException {
this.port = port;
this.ssc = ServerSocketChannel.open();
this.ssc.socket().bind(new InetSocketAddress(port));
this.ssc.configureBlocking(false);
this.selector = Selector.open();
this.ssc.register(selector, SelectionKey.OP_ACCEPT);
}
@Override public void run() {
try {
System.out.println("Server starting on port " + this.port);
Iterator<SelectionKey> iter;
SelectionKey key;
while(this.ssc.isOpen()) {
selector.select();
iter=this.selector.selectedKeys().iterator();
while(iter.hasNext()) {
key = iter.next();
iter.remove();
if(key.isAcceptable()) this.handleAccept(key);
if(key.isReadable()) this.handleRead(key);
}
}
} catch(IOException e) {
System.out.println("IOException, server of port " +this.port+ " terminating. Stack trace:");
e.printStackTrace();
}
}
private final ByteBuffer welcomeBuf = ByteBuffer.wrap("Welcome to NioChat!\n".getBytes());
private void handleAccept(SelectionKey key) throws IOException {
SocketChannel sc = ((ServerSocketChannel) key.channel()).accept();
String address = (new StringBuilder( sc.socket().getInetAddress().toString() )).append(":").append( sc.socket().getPort() ).toString();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ, address);
sc.write(welcomeBuf);
welcomeBuf.rewind();
System.out.println("accepted connection from: "+address);
}
private void handleRead(SelectionKey key) throws IOException {
SocketChannel ch = (SocketChannel) key.channel();
StringBuilder sb = new StringBuilder();
buf.clear();
int read = 0;
while( (read = ch.read(buf)) > 0 ) {
buf.flip();
byte[] bytes = new byte[buf.limit()];
buf.get(bytes);
sb.append(new String(bytes));
buf.clear();
}
String msg;
if(read<0) {
msg = key.attachment()+" left the chat.\n";
ch.close();
}
else {
msg = key.attachment()+": "+sb.toString();
}
System.out.println(msg);
broadcast(msg);
}
private void broadcast(String msg) throws IOException {
ByteBuffer msgBuf=ByteBuffer.wrap(msg.getBytes());
for(SelectionKey key : selector.keys()) {
if(key.isValid() && key.channel() instanceof SocketChannel) {
SocketChannel sch=(SocketChannel) key.channel();
sch.write(msgBuf);
msgBuf.rewind();
}
}
}
public static void main(String[] args) throws IOException {
NiochatServer server = new NiochatServer(10523);
(new Thread(server)).start();
}
}

@abhi9090

why to use nio for doing a chatapplication...when we can simply do it using socket programming easily ?

@Botffy
Owner
Botffy commented on 8 Sep 2015

Because nio is non-blocking, so doesn't require additional threads. A socket-based chat would require as many threads as there are users, adding a significant overhead, while a nio chat would always need but one thread, making it a lot more scalable, as the overhead of threading may get really significant.

@jorkey
jorkey commented on 27 Mar

Why you are not check number of bytes written on channel.write()?
Some bytes may be not be written because no free space in the socket's output buffer.

@babs93
babs93 commented on 4 Apr

Where is the client NIO code?


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

반응형


관련글 더보기

댓글 영역