Java non blocking NIO case (realize multi person chat function)

Keywords: Java network Junit

I. three cores of using Java NIO to complete network communication

1. Channel: responsible for connection

java.nio.channels.Channel interface:
              |--SelectableChannel
                  |--SocketChannel
                  |--ServerSocketChannel
                  |--DatagramChannel
 
                  |--Pipe.SinkChannel
                  |--Pipe.SourceChannel

2. buffer: responsible for data access

3. Selector: it is the multiplexer of the selectable channel, which is used to detect the IO status of the selectable channel

 

Case: using non blocking to realize simple group chat system

I. implementation of client

 1     public static void main(String[] args) throws Exception {
 2         SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8989));
 3 
 4         //2. Switch non blocking mode
 5         sChannel.configureBlocking(false);
 6 
 7         //3. Allocate buffer of specified size
 8         ByteBuffer buf = ByteBuffer.allocate(1024);
 9 
10         //4. Send data to the server
11         Scanner scan = new Scanner(System.in);
12 
13         while (scan.hasNext()) {
14             String str = scan.next();
15             buf.put((new Date().toString() + "\n" + str).getBytes());
16             buf.flip();
17             sChannel.write(buf);
18             buf.clear();
19         }
20 
21         //5. Close channel
22         sChannel.close();
23     }

2. Realize the server

    @Test
    public void server() {
        ServerSocketChannel ssChannel = null;
        try {
            ssChannel = ServerSocketChannel.open();
            //Configure non blocking
            ssChannel.configureBlocking(false);
            //Binding connection
            ssChannel.bind(new InetSocketAddress(8989));

            Selector selector = Selector.open();

            //Register the channel to the listener, and set the listener's listening mode as "accept"
            ssChannel.register(selector, SelectionKey.OP_ACCEPT);

            //Events for which polling selection is ready
            while (selector.select() > 0) {
                //Get current listening
                Iterator<SelectionKey> it = selector.selectedKeys().iterator();

                while (it.hasNext()) {
                    //Get ready events
                    SelectionKey sk = it.next();
                    if (sk.isAcceptable()) {
                        //If ready to accept, get the client's connection
                        SocketChannel clientChannel = ssChannel.accept();

                        //Also configured as non blocking
                        clientChannel.configureBlocking(false);

                        //Register the client's connection to the selector
                        clientChannel.register(selector, SelectionKey.OP_READ);
                    } else if (sk.isReadable()) {
                        //If the read is ready, get the read channel
                        SocketChannel socketChannel = (SocketChannel) sk.channel();

                        //Configure to non blocking mode
                        socketChannel.configureBlocking(false);

                        //Read data

                        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

                        int len = 0;
                        while ((len = socketChannel.read(byteBuffer)) > 0) {
                            byteBuffer.flip();
                            System.out.println(new String(byteBuffer.array(), 0, len));
                            byteBuffer.clear();
                        }
                    }
                    it.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(ssChannel!=null){
                try {
                    ssChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

Note: here is the org.junit.Test used by the server. This package is convenient for testing. Because the client needs to read the input, it is written in the Main function (@ Test method seems unable to read the input)

The address to download the package is as follows:

Link: https://pan.baidu.com/s/14zhhonad3ldnvcaa3pmcojq
Extraction code: uqd9

How to use datagram channel (UDP) (similar to the previous case)

public static void main(String args[]) {
        DatagramChannel datagramChannel = null;
        try {
            datagramChannel = DatagramChannel.open();

            datagramChannel.configureBlocking(false);

            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

            Scanner scanner = new Scanner(System.in);

            while (scanner.hasNext()) {
                String str = scanner.next();
                byteBuffer.put(str.getBytes());
                byteBuffer.flip();
                datagramChannel.send(byteBuffer, new InetSocketAddress("127.0.0.1", 9897));
                byteBuffer.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            if(datagramChannel!=null){
                try {
                    datagramChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Test
    public void server(){
        DatagramChannel datagramChannel = null;
        try {
            datagramChannel=DatagramChannel.open();
            datagramChannel.bind(new InetSocketAddress(9897));

            datagramChannel.configureBlocking(false);

            Selector selector = Selector.open();
            datagramChannel.register(selector, SelectionKey.OP_READ);

            while(selector.select()>0){
                Iterator<SelectionKey> st=selector.selectedKeys().iterator();

                while(st.hasNext()){
                    SelectionKey sk=st.next();

                    if(sk.isReadable()){
                        ByteBuffer btf=ByteBuffer.allocate(1024);

                        datagramChannel.receive(btf);

                        btf.flip();

                        System.out.println(new String(btf.array(),0,btf.limit()));
                        btf.clear();
                    }
                }
                st.remove();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(datagramChannel!=null){
                try {
                    datagramChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

 

Pipe introduction

Pipe is a single data connection between two threads. Pipe has two data channels. The Sign channel is responsible for writing and the Source channel is responsible for reading.
The cases are as follows:
    @Test
    public void test() throws Exception {
        Pipe pipe = Pipe.open();

        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        byteBuffer.put("hello world".getBytes());

        Pipe.SinkChannel sinkChannel=pipe.sink();
        byteBuffer.flip();
        sinkChannel.write(byteBuffer);


        //read

        Pipe.SourceChannel sourceChannel =pipe.source();
        byteBuffer.flip();
        int len=sourceChannel.read(byteBuffer);

        System.out.println("sourceChanel:"+new String(byteBuffer.array(),0,len));
        byteBuffer.clear();

        sinkChannel.close();

        sourceChannel.close();

    }

 

 

Thank you for browsing. If you have any questions, I will change my mistakes in time.

Posted by gergy008 on Tue, 03 Dec 2019 06:06:53 -0800