javaNIO learning notes

javaNIO learning notes (2)

Reference documents: http://tutorials.jenkov.com/java-nio/channels.html

Java NIO Channel

Compared with InputStream and OutputStream in traditional IO, the main difference is that the stream in traditional IO is unidirectional. But channels in NIO are readable and writable. And reading and writing can be done asynchronously. In addition, channels read or write data from the buffer

The main implemented pipeline types in the previous learning notes

  • FileChannel reads data from files and files

  • Datagram channel can read and write data on the network through UDP.

  • SocketChannel can read and write data on the network through TCP.

  • ServerSocketChannel allows you to listen for incoming TCP connections, just like a web server. Create a SocketChannel for each incoming connection.

These four classes can view the corresponding UML diagram in idea

FileChannel

First look at the following procedure

Read file data:

public class FileChannelPrc {

    public static void main(String[] args) throws IOException {
        // Create a random file of rw mode
        RandomAccessFile randomAccessFile =new RandomAccessFile("D:\\nioFile.txt", "rw");
        // Get fileChinnel
        FileChannel fileChannel = randomAccessFile.getChannel();

        // Set buffer size 48
        ByteBuffer buf = ByteBuffer.allocate(48);
        
        int bytesRead = fileChannel.read(buf);
        while(bytesRead !=-1){
            System.out.println("\nRead " + bytesRead);
            
            buf.flip();

            while(buf.hasRemaining()){
                System.out.print((char) buf.get());
            }

            buf.clear();
            bytesRead = fileChannel.read(buf);
        }
        randomAccessFile.close();
    }
}

// Operation result:
Hi, I am jimmy. 

To execute the above program correctly, create the corresponding file in the local corresponding folder. What I write in the file is Hi, I am jimmy. Here you can see that it is read out and printed.

Then we change the contents of the file to Hi, I am jimmy. I am learning Java NIO. Hope I can hold it. When running the program, return the value

Read 48
Hi, I am jimmy. I am learning Java NIO. Hope I
Read 13
can hold it.

We can probably guess through the above test.

// Read the data to the buffer through fileChannel, and the return value is the number of bytes read by the buffer
int bytesRead = fileChannel.read(buf);
// Determine whether there is data in the buffer
buf.hasRemaining()
// Gets the first element of the current buffer
buf.get()
// Toggle buffer read / write mode    
buf.flip();
// Clear cache
buf.clear();

Let's just look at the channel related guesses. Transformation procedure (the transformation part is as follows)

// Set buffer size
ByteBuffer buf = ByteBuffer.allocate(48);
ByteBuffer buf2 = ByteBuffer.allocate(48);
int bytesRead = fileChannel.read(buf);
int bytesRead2 = fileChannel.read(buf);
System.out.println("bytesRead" + bytesRead + "  bytesRead2" + bytesRead2);

At this time, you can see that bytesread = 16 bytesread2 = - 1 (file information Hi, I am jimmy.). Then we can draw a conclusion

fileChannel.read(buf); will flush the channel's data to the buffer instead of copying.

The following program uses fileChannel to write information to files

public class FileChannelPrc {

    public static void main(String[] args) throws IOException {
       
        ...
        // Write file
//        ByteBuffer buf2 = ByteBuffer.allocate(48);
        String newData = "do not worry, be happy Time:" + System.currentTimeMillis();
        buf.clear();
        buf.put(newData.getBytes());
        while(buf.hasRemaining()) {
             buf.flip();
            fileChannel.write(buf);
        }

        fileChannel.close();
        randomAccessFile.close();
    }
}

View file, file text display

Hi, I am jimmy. do not worry, be happy Time: 1591970658685

It can be seen from the results that when fileChannel writes data, it adds write data at the end of the file instead of overwriting.

According to the above example, we will briefly summarize the simple use of fileChannel.

  • Obtain the instance of fileChannel (note that public abstract class FileChannel is an abstract class). How to get it

You can use an instance of RandomAccessFile to get

  • The method of reading data uses read to read the content to ByteBuffer. Of course, the use of ByteBuffer is also designed here, which will be summarized later
  • The write process uses the write method to write the ByteBuffer information to the file.
  • Of course, like traditional IO, you need to call close to close fileChannel

Next, take a look at the source code of fileChannel (this is also a memo. You can come back to take a look when you encounter related problems, which may help.)

// ----read method-------
public abstract int read(ByteBuffer dst) throws IOException;
// Read data from specified location
public abstract int read(ByteBuffer dst, long position) throws IOException;
public final long read(ByteBuffer[] dsts) throws IOException {
        return read(dsts, 0, dsts.length);
}
public abstract long read(ByteBuffer[] dsts, int offset, int length) throws IOException;

// ------write method------
public abstract int write(ByteBuffer src) throws IOException;
public abstract int write(ByteBuffer src, long position) throws IOException;
public final long write(ByteBuffer[] srcs) throws IOException {
    return write(srcs, 0, srcs.length);
}
public abstract long write(ByteBuffer[] srcs, int offset, int length) throws IOException;

// ----open method - @ since 1.7 can get fileChannel
public static FileChannel open(Path path, OpenOption... options) throws IOException
{
    Set<OpenOption> set = new HashSet<OpenOption>(options.length);
    Collections.addAll(set, options);
    return open(path, set, NO_ATTRIBUTES);
}
public static FileChannel open(Path path,  Set<? extends OpenOption> options,
                                   FileAttribute<?>... attrs) throws IOException
{
    FileSystemProvider provider = path.getFileSystem().provider();
    return provider.newFileChannel(path, options, attrs);
}

// ---  position  --
// Get a new fileChannel
 public abstract FileChannel position(long newPosition) throws IOException;
// Return the location of buffer read
public abstract long position() throws IOException;
// --- force  ----
// Force the data of the channel to be written, and decide whether to write to the local disk storage according to the metaData
public abstract void force(boolean metaData) throws IOException;
// Returns the current size of this channel's file
public abstract long size() throws IOException;
// Intercept the data of specified length, and intercept the data of size from the beginning
public abstract FileChannel truncate(long size) throws IOException;

Of course, there are some other methods, which will be supplemented later when it comes to use. The code at the time of test is attached here (not all, some API s can directly use the fragments of idea to view the results.)

public class FileChannelPrc {

    public static void main(String[] args) throws IOException {
        // Create a random file of rw mode
        RandomAccessFile randomAccessFile =new RandomAccessFile("D:\\nioFile.txt", "rw");
        // Get fileChinnel
        FileChannel fileChannel = randomAccessFile.getChannel();

//        fileChannel.position();
        FileChannel fileChannel2 = fileChannel.truncate(10);
        // Set buffer size
        ByteBuffer buf = ByteBuffer.allocate(48);

//        int bytesRead = fileChannel.read(buf,10L);
        int bytesRead = fileChannel2.read(buf);

//        ByteBuffer buf2 = ByteBuffer.allocate(48);

//        int bytesRead = fileChannel.read(buf);
        /*int bytesRead2 = fileChannel.read(buf);
        System.out.println("bytesRead" + bytesRead + "  bytesRead2" + bytesRead2);*/
        while(bytesRead !=-1){
            System.out.println("Read " + bytesRead);
            buf.flip();

            while(buf.hasRemaining()){
                System.out.print((char) buf.get());
            }

            buf.clear();
//            bytesRead = fileChannel.read(buf);
            bytesRead = fileChannel2.read(buf);
        }

        // Write file
//        ByteBuffer buf2 = ByteBuffer.allocate(48);
       /* String newData = "do not worry, be happy Time:+ System.currentTimeMillis();
        buf.clear();
        buf.put(newData.getBytes());
        while(buf.hasRemaining()) {
            buf.flip();
            fileChannel.write(buf);
        }*/

        fileChannel.close();
        randomAccessFile.close();
    }
}

SocketChannel and ServerSocketChannel

Socketchannel is a channel used to process TCP network sockets. There are two ways to get socketchannel

  • You can get an instance directly by using open()
  • Get through ServerSocketChannel
SocketChannel socketChannel = SocketChannel.open();

The ServerSocketChannel is similar to the ServerSocket in the standard Java network. It is a channel that can listen for incoming TCP connections

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

no talk´╝îshow code

package jniolearn.channel;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

/**
 * @Author: jimmy
 * @Date: 2020/6/13 15:03
 * @Description:
 *
 * Understand as server
 */
public class ServerSocketChannelPrc {

    public static void main(String[] args) throws IOException {

        // Get instance
        ServerSocketChannel server = ServerSocketChannel.open();
        // Binding ip and port
        server.socket().bind(new InetSocketAddress("127.0.0.1",2999));
        //Set to non blocking mode
        server.configureBlocking(false);
        // Get SocketChannel
        while(true){
            SocketChannel serverChannel =  server.accept();

            if(serverChannel != null) {
                ByteBuffer buf = ByteBuffer.allocate(512);
                int byteRead = serverChannel.read(buf);

                StringBuilder req = new StringBuilder();
                buf.flip();
                while(buf.hasRemaining()){
                    req.append((char) buf.get());
                }
                buf.clear();

                System.out.println("Message from client" + req);

                buf.put("hi,this is jimmy. be happy ".getBytes());
                buf.flip();
                serverChannel.write(buf);

    //        serverChannel.close();
            }
        }
    }
}


package jniolearn.channel;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

/**
 * @Author: jimmy
 * @Date: 2020/6/13 12:04
 * @Description:
 *
 * It can be understood as client
 */
public class SocketChannelPrc {

    /**
     * For convenience, throw the exception directly here. The actual development needs to catch the exception
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {

        //  Get an instance of SocketChannel
        SocketChannel client = SocketChannel.open();
        /**
         * Connect to the server. The parameter object passed in is SocketAddress
         * Check the source code to find an implementation class InetSocketAddress construction method public InetSocketAddress(String hostname, int port)
         * I'm familiar with this structure,
         *
         * Connecting services 127.0.0.1 and 2999 ports
         */
        client.connect(new InetSocketAddress("127.0.0.1",2999));

        // A channel requires a buffer
        ByteBuffer buf = ByteBuffer.allocate(512);
        buf.put("hi, jimmy,this is client.".getBytes());
        // Switch between read and write mode
        buf.flip();
        // Write data to server
        client.write(buf);
        // Clear the buffer, which is equivalent to resetting the buffer to read mode
        buf.clear();
        int byteRead =  client.read(buf);
        buf.flip();
        StringBuilder stringBuffer=new StringBuilder();
        while (buf.hasRemaining()){
            stringBuffer.append((char) buf.get());
        }
        buf.clear();

        System.out.println("Data received from the server:"+stringBuffer);

        // Close socketChannel
        client.close();
    }
}

Start ServerSocketChannel on the server, and then U starts SocketChannel. The return result is as follows:

hi, jimmy,this is client

Data received from the server: hi,this is jimmy. be happy

Generally speaking, it's not much different from fileChannel. Basically, you need to have an open channel first (there's a way to get whether it's open or not). The corresponding buffer is then used to write data from the channel to the buffer or read data from the buffer. (the buffer related methods will be studied later.). However, some special points should be noted: configureBlocking() a method of socketchannel indicates whether the socketchannel 'serversocketchannel is blocked or non blocked. When learning the selector, you should supplement it. Of course, the above program is not perfect, and an error will be reported when the receiving buffer is not large enough. You can change the code to see.

DatagramChannel

DatagramChannel is similar to DatagramSocket class of java network programming; UDP is used for network transmission

Similarly, you can use the open method to get an instance

package jniolearn.channel;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;

/**
 * @Author: jimmy
 * @Date: 2020/6/13 17:32
 * @Description:
 * server
 */
public class DatagramChannelPrcS {

    public static void main(String[] args) throws IOException {
        DatagramChannel s = DatagramChannel.open();
        s.bind(new InetSocketAddress("127.0.0.1",3999));
        ByteBuffer buf = ByteBuffer.allocate(48);
        s.receive(buf);
        buf.clear();
        while(buf.hasRemaining()){
            System.out.print((char)buf.get());
        }

    }
}

package jniolearn.channel;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;

/**
 * @Author: jimmy
 * @Date: 2020/6/13 17:26
 * @Description:
 * client
 */
public class DatagramChannelPrc {

    public static void main(String[] args) throws IOException {

        DatagramChannel channel = DatagramChannel.open();
        // Bind port
//        channel.bind(new InetSocketAddress(3999));

        ByteBuffer buf = ByteBuffer.allocate(48);
        buf.put("datagrameChannel info".getBytes());
        // Datagram channel does not need to use this method
//        channel.write(buf);
        buf.flip();
        int a = channel.send(buf,new InetSocketAddress("127.0.0.1",3999));
        channel.close();
    }
}

It is relatively simple to use. The server can directly use bind method to bind port and ip. The client sends the data directly from the buffer to the server. There is no guarantee whether the message is sent successfully or received successfully. The send message is sent through the send method. The change method returns an int value, indicating the number of bytes successfully sent:

So one of the tails of this learning is about the difference and application between blocking mode and non blocking mode. This is a supplementary study after learning other classes

buf = ByteBuffer.allocate(48);
buf.put("datagrameChannel info".getBytes());
//Datagram channel does not need to use this method
// channel.write(buf);
buf.flip();
int a = channel.send(buf,new InetSocketAddress("127.0.0.1",3999));
channel.close();
}
}

It is relatively simple to use. The server can directly use bind method to bind port and ip. The client sends the data directly from the buffer to the server. There is no guarantee whether the message is sent successfully or received successfully. The send message is sent through the send method. The change method returns an int value, indicating the number of bytes successfully sent:



So the tail of this learning is about the difference and application between blocking mode and non blocking mode. This is a supplementary study after learning other classes











Tags: Java network Web Server socket

Posted on Sat, 13 Jun 2020 07:04:17 -0400 by thegreatone2176