Recently, I plan to deepen my knowledge of Java network programming (IO, NIO, Socket programming, Netty).

Java I/O streams

Java Network Programming

Java NIO: Buffers

Java NIO: Channels

Java NIO: selector

Java I/O is built on streams. The input stream reads data and the output stream writes data

Input-output stream

The input stream

The API for InputStream is as follows:

public abstract int read(a) throws IOException;/ / - 1 to 255
public int read(byte b[]) throws IOException 
public int read(byte b[], int off, int len) throws IOException
public long skip(long n) throws IOException
public int available(a) throws IOException
public void close(a) throws IOException 
Copy the code

The read() method actually returns an unsigned byte(Java doesn’t have an unsigned byte, so int is returned).

The read method returns -1 to indicate that the data has been read (or, in the case of network communication, that the peer end will not send any more data)

The output stream

The output stream OutputStreamAPI is as follows:

// The OutputStream interface defines several methods
public abstract void write(int b) throws IOException;
public void write(byte b[]) throws IOException 
public void write(byte b[], int off, int len) throws IOException
public void flush(a) throws IOException
public void close(a) throws IOException
Copy the code

The write(int) method actually writes the lower 8 bits (one byte) of int.

Try not to use write(int), because sending one byte at a time is inefficient (each TCP packet has at least 40 bytes of network transmission overhead, and the channel utilization rate is not high if the data is too small).

Flush () flushes the contents of the buffer to the underlying output stream

Close the stream

The stream corresponds to the underlying file handle and port, so be sure to close it when you’re done using it

The following is a common way to close a stream (ina finally statement block), but it’s too complicated!!

	FileInputStream in = null;
  try {
    in = new FileInputStream("/tmp/axt.t");
    //
  } catch (FileNotFoundException e) {
    //
  } finally {
    if(in ! =null) {try {
        in.close();
      } catch (IOException e) {
        //}}}Copy the code

Let me write it a little bit neater

try(FileInputStream in = new FileInputStream("/tmp/a.txt")) {// do somethind
} catch (Exception e) {
   //
}

Copy the code

Because Java automatically calls the close() method on all objects of type AutoCloseable declared in the try block, there is no need to call it manually!

The filter flow

The filter flow is actually an enhancement of the flow function, using decorator mode.

Decorative pattern

Decoration mode is to add some new functions on the basis of the original, through combination.

Below is the filter flow class structure – the embodiment of the decorator pattern

The role of filter flow

The following code wraps FileInputStream with BufferedInputStream and DataInputStream

Allows the user to read characters directly from the Java buffer (if no data is available in the buffer, try reading from the underlying input stream)

FileInputStream in = new FileOutputStream("/tmp/a.txt");
in = new BufferedInputStream(in);
in = new DataInputStream(in);
in.readChar();
Copy the code

Filter streams can also be decompressed (ZIPInputStream), Base64InputStream decoded (Base64InputStream), and can also be customized for specific functions.

Buffer flow

Buffer flow is a kind of filter flow. In network communication scenarios, buffering improves the efficiency of sending and receiving data.

We should use BufferedOutputStream when sending data, so that the data is written to the Java buffer first, and the data is not sent until the buffer is full or the flush method is called.

 OutputStream out = new FileOutputStream("/tmp/a.txt");
 BufferedOutputStream outputStream = new BufferedOutputStream(out);
 out.write(1);
 out.flush();
Copy the code

The data flow

Buffered flows, as one of the filter flows, provide apis for reading and writing Java primitive types directly

 OutputStream out = new FileOutputStream("/tmp/a.txt");
 DataOutputStream  dataOutputStream = new DataOutputStream(out);
 dataOutputStream.writeChar('c'); / / write characters
 dataOutputStream.writeUTF("ssss"); // Write a string
Copy the code

Readers and writers

Provides an API for reading and writing characters (if only ASCII encoding, use byte stream directly)

writer

OutputStreamWriter provides the ability to read characters and strings directly

OutputStream out = new FileOutputStream("/tmp/a.txt"); // The bottom byte stream
Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);
writer.write("Ha ha ha.");
Copy the code

Buffer writer

BufferedWriter Provides a layer of write buffering (a BufferedOutputStream that acts like a byte stream)

Demo

 				OutputStream out = new FileOutputStream("/tmp/a.txt"); // The bottom byte stream
        Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);// write (encoding)
        writer = new BufferedWriter(writer, 1000);// Buffer writer
        for (int i = 0; i < 128; i ++){
            writer.write(i); 
        }
        writer.write("Ha ha ha ha ha.");// Write Chinese characters, utF-8 encoding visible, ASCII encoding will be garbled
        writer.flush(); // We don't need to flush, we should flush before close.
        writer.close(); // Close the flow to release the underlying resources.

Copy the code

conclusion

The total is divided into two types of byte stream and character stream. Character stream is just a decoration of byte stream (or the bottom layer of character stream is byte stream).

Filter stream: Add some additional features to the base stream such as buffering, compression, encryption, etc

Buffer flow: A buffer layer is added between read and write data to improve data transmission efficiency.