Netty’s IO principle one

Netty is an asynchronous event-driven network application framework
for rapid development of maintainable high performance protocol servers & clients.

Netty features:

1. Asynchronous event-driven (asynchronous event-driven)

2. Maintainability (maintainable)

3. Construction of high-performance protocol servers & clients (high performance protocol servers & clients)

4. The three highs of the Internet: high availability, high performance, and high concurrency

Internet top three? It is to throw the server into the context of the Internet and some characteristics that need to be met.

Constraints generated by attributes:
1. Ensure server high performance (throughput, latency)
What is latency?

JVM latency is for user programs and GC threads. The time from when a request arrives at the JVM to when the JVM returns the request is called the JVM latency.

If you look at latency from a thread perspective, there are two types, one is the latency of the user thread, and the other is the latency of the GC thread.

GC thread latency: the time it takes from when GC starts to end.

User thread delay: The time it takes from function entry to completion, because the user thread executes the function. Generally speaking, it is the time it takes from the time he starts to finish something.

What is throughput?

2. Ensure high server concurrency (ensure high performance based on a large number of users)
3. Ensure high server availability

NIO three major components: Channel, Buffer, Selector

Why is Channel defined as an interface? Why is buffer defined as an abstract class?

Determined by the JSR-51 Expert Group. The biggest difference between an abstract class and an interface is that an abstract class is a class, and an interface is not a class. The interface has no implementation and cannot define its own template methods. Buffer is a buffer. Buffers have a common parent class and common operations. Some basic characteristics of the buffer need to be defined:

private int mark = -1;
private int position = 0;
private int limit;
private int capacity;
long address;

So Buffer must use an abstract class.

Traditional IO reading:

//Just take the file stream as an example
public abstract class InputStream implements Closeable {
    public int read(byte b[]) throws IOException {
        return read(b, 0, b.length); // Directly call the read(byte b[], int off, int len) function
    }

    public int read(byte b[], int off, int len) throws IOException {
        if (b == null) { // Check whether the byte array is empty
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) { // Verify whether the read range is correct
            throw new IndexOutOfBoundsException();
        } else if (len == 0) { // Verify read length
            return 0;
        }
        //*Call the read() function to read one byte, byte by byte.
        int c = read();
        if (c == -1) { // Verify that the bytes have reached the end of the file
            return -1;
        }
        b[off] = (byte)c; // Save the byte data into the b array
        int i = 1;
        try {
            //Read the file data from the disk byte by byte and put it into the b byte array
            for (; i < len ; i + + ) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
        }
        return i;
    }
}
Write:
public abstract class OutputStream implements Closeable, Flushable {
    public void write(byte b[]) throws IOException {
        write(b, 0, b.length); // Directly call the write(byte b[], int off, int len) function
    }

    public void write(byte b[], int off, int len) throws IOException {
        if (b == null) { // Check array cannot be empty
            throw new NullPointerException();
        } else if ((off < 0) || (off > b.length) || (len < 0) ||
                   ((off + len) > b.length) || ((off + len) < 0)) { // Verify whether the writing range is reasonable
            throw new IndexOutOfBoundsException();
        } else if (len == 0) { // Verify whether the written length is 0
            return;
        }
        //*Loop to write the data in the b array to the file byte by byte
        for (int i = 0 ; i < len ; i + + ) {
            write(b[off + i]);
        }
    }
}
General IO principle: processing byte by byte, the performance is too poor.

Later, FileInputStream rewrote the read and write methods.

public int read(byte b[]) throws IOException {
    return readBytes(b, 0, b.length);
}
private native int readBytes(byte b[], int off, int len) throws IOException;

So it is still useful to add a buffer, which can read a batch of data at once.

BIO model:

NIO model:

NIO read:

readBytes method and writeBytes underlying implementation principle
jint readBytes(JNIEnv *env, jobject this, jbyteArray bytes,
               jint off, jint len, jfieldID fid){
    ...
        if (len == 0) {
        return 0;
    } else if (len > BUF_SIZE) {
        buf = malloc(len); // allocate a space
    }
    ...
            if (fd == -1) {
        ...
        } else {
        nread = IO_Read(fd, buf, len); // Call the read function to read data
        if (nread > 0) {
            // Save the data into the bytes array of heap memory
            (*env)->SetByteArrayRegion(env, bytes, off, nread, (jbyte *)buf);
        }
        ...
        }
    ...
    }

void writeBytes(JNIEnv *env, jobject this, jbyteArray bytes,
                jint off, jint len, jboolean append, jfieldID fid){
    ...
    if (len == 0) {
        return;
    } else if (len > BUF_SIZE) {
        buf = malloc(len); // allocate a space
        ...
        }
    ...
    //Copy the contents of the bytes array in the java heap memory space to buf
    (*env)->GetByteArrayRegion(env, bytes, off, len, (jbyte *)buf);

    if (!(*env)->ExceptionOccurred(env)) {
        off = 0;
        while (len > 0) {
            ...
            if (append == JNI_TRUE) {
                ...
                } else {
                n = IO_Write(fd, buf + off, len); // Write the data in buf to the OS
            }
            ...
            }
    }
    ...
    }

Introducing the principles of direct memory and heap memory from JVM memory:

Why do we need a local variable table? Equivalent to the registers and storage units in the CPU, the operand stack simulates the ALU unit, and the constant pool pointer is used to obtain metadata.

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Java Skill TreeIO Flow Overview 138643 people are learning the system