IO model
The IO model refers to what channel is used to send and receive data.
In the book Unix network programming, five IO models are mentioned, namely, blocking IO, non blocking IO, multiplexing IO, signal driven IO and asynchronous io
Java supports three network programming IO modes: BIO (blocking IO), NIO (non blocking IO), AIO (asynchronous non blocking IO)
BIO(Blocking IO)
Synchronous blocking IO means that a client connection corresponds to a processing thread.
When I first learned Java, I / O flows belonged to the BIO model.
shortcoming
1) Read operation in IO code is blocking operation. If the connection does not read and write data, it will lead to thread blocking and waste resources.
2) If there are many threads, it will lead to too many server threads and too much pressure.
Application scenario
BIO mode is applicable to the architecture with small and fixed connections. This mode requires high server resources, but the program is simple and easy to understand.
Code example
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * Socket Stream socket server * ... */ public class SocketServer { public static void main(String[] args) throws IOException { // Create a server socket and bind to the specified port. ServerSocket serverSocket = new ServerSocket(9999); // Dead circulation ensures that the server is always running online while (true) { System.out.println("Server waiting for connection:" + System.currentTimeMillis()); // Listen to the connection to be established to this socket and accept it. This method will block until a connection is established. final Socket socket = serverSocket.accept(); System.out.println("Listen to the client and establish a connection"); new Thread(new Runnable() { public void run() { try { handler(socket); } catch (IOException e) { e.printStackTrace(); } } }).start(); } } private static void handler(Socket socket) throws IOException { System.out.println("Thread ID = " + Thread.currentThread().getId()); byte[] bytes = new byte[1024]; System.out.println("prepare read"); // Receiving data from the client is also a blocking method. Blocking occurs when there is no data readable int read = socket.getInputStream().read(bytes); System.out.println("read complete"); if (read != -1) { System.out.println("Data received from client:" + new String(bytes, 0, read)); System.out.println("Thread ID = " + Thread.currentThread().getId()); } // Write out data in response to the client socket.getOutputStream().write("HelloClient".getBytes()); socket.getOutputStream().flush(); } }
import java.io.IOException; import java.net.Socket; /** * Socket Stream socket client * ... */ public class SocketClient { public static void main(String[] args) throws IOException { // Create a stream socket and connect it to the specified host port Socket socket = new Socket("localhost", 9999); // Send data to the server socket.getOutputStream().write("HelloServer".getBytes()); socket.getOutputStream().flush(); System.out.println("End of sending data from client to server!"); byte[] bytes = new byte[1024]; // Receive server response data socket.getInputStream().read(bytes); System.out.println("Received data from the server:" + new String(bytes)); // Close stream socket socket.close(); } }
BIO model
NIO(Non Blocking IO)
Synchronous non blocking io. The server implementation mode is that one thread can process multiple requests (connections). The connection requests sent by the client will be registered on the multiplexer selector, and the multiplexer will process the IO requests after polling the connection. The bottom layer of I/O multiplexing is generally implemented by Linux API s (select, poll, epoll). Their differences are as follows:
Application scenario
NIO mode is applicable to the architecture with a large number of connections and relatively short connections (light operation), such as chat server, barrage system, communication between servers, and complex programming. JDK1.4 starts to support it;
NIO model
NIO has three core components: buffer, channel and selector
1) Channels are similar to streams. Each channel corresponds to a buffer, and the underlying buffer is an array
2) The channel will be registered with the selector, and the selector will send it to an idle thread to process according to the occurrence of the channel read-write event
3) A selector can correspond to one or more threads
4) NIO's Buffer and channel can be read or written
Code example
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; /** * NIO Server * ... */ public class NioServer { public static void main(String[] args) throws IOException { // Create a service Socket channel that listens on the local port ServerSocketChannel ssc = ServerSocketChannel.open(); // Set non blocking mode. Otherwise, an error will be reported. The selector mode itself is a non blocking mode ssc.configureBlocking(false); // Binding port ssc.socket().bind(new InetSocketAddress(9999)); // Create a selector Selector selector = Selector.open(); // Register the ServerSocketChannel to the selector, and the selector is interested in the client accept connection operation ssc.register(selector, SelectionKey.OP_ACCEPT); // Infinite circulation ensures the online operation of the server while (true) { System.out.println("The server waits for the event to occur"); // Poll the key in the listening channel, select is blocked, and accept() is also blocked int select = selector.select(); System.out.println("Something happened="+select); // There is a client request, which is polled and monitored Iterator<SelectionKey> it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey key = it.next(); // Delete the currently processed key to prevent repeated processing in the next select ion it.remove(); // Process the monitored key handle(key); } } } private static void handle(SelectionKey key) throws IOException { if (key.isAcceptable()) { System.out.println("Connection event"); ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); // NIO non blocking embodiment: the accept method here is blocked, but because a connection event occurred here, this method will be executed immediately without blocking // After processing the connection request, it will not continue to wait for the data sent by the client SocketChannel sc = ssc.accept(); sc.configureBlocking(false); // Interested in reading events when listening to channels through Selector sc.register(key.selector(), SelectionKey.OP_READ); } else if (key.isReadable()) { System.out.println("Data readable events"); SocketChannel sc = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); // NIO non blocking embodiment: firstly, the read method will not block. Secondly, in this event response model, when the read method is called, the event that the client sends data must occur int len = sc.read(buffer); if (len != -1) { System.out.println("Read the data sent by the client:" + new String(buffer.array(), 0, len)); } ByteBuffer bufferToWrite = ByteBuffer.wrap("HelloClient".getBytes()); sc.write(bufferToWrite); key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); } else if (key.isWritable()) { SocketChannel sc = (SocketChannel) key.channel(); System.out.println("write event"); // NIO event trigger is horizontal trigger // When using Java NIO programming, cancel writing events when there is no data to write out, // Register the write event when there is data written out key.interestOps(SelectionKey.OP_READ); // sc.close(); } } }
NIO server program steps
1) Create a ServerSocketChannel and Selector, and register the ServerSocketChannel with the Selector
2) The selector listens to the channel event through the select() method. When the client connects, the selector listens to the connection event and obtains the selectionKey bound when the ServerSocketChannel is registered
3) selectionKey can obtain the bound ServerSocketChannel through the channel() method
4) ServerSocketChannel gets SocketChannel through accept() method
5) Register SocketChannel on the Selector and pay attention to the read event
6) After registration, a SelectionKey is returned, which is associated with the SocketChannel
7) The selector continues to listen for events through the select() method. When the client sends data to the server, the selector listens to the read event and obtains the selectionKey bound when the SocketChannel is registered
8) selectionKey can obtain the bound socketChannel through the channel() method
9) Read out the data in socketChannel
10) Write the server data back to the client with socketChannel
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.Iterator; /** * NIO client * ... */ public class NioClient { // Channel Manager private Selector selector; /** * Start client test * * @throws IOException */ public static void main(String[] args) throws IOException { NioClient client = new NioClient(); client.initClient("127.0.0.1", 9999); client.connect(); } /** * Get a Socket channel, and do some initialization work for this channel * * @param ip ip of the connected server * @param port Port number of the connected server * @throws IOException */ public void initClient(String ip, int port) throws IOException { // Get a Socket channel SocketChannel channel = SocketChannel.open(); // Set channel to non blocking channel.configureBlocking(false); // Get a channel manager this.selector = Selector.open(); // The client connects to the server. In fact, the method execution does not realize the connection. You need to call channel in the listen() method finishConnect(); To complete the connection channel.connect(new InetSocketAddress(ip, port)); // Bind the channel manager to the channel and register OP for the channel_ Connect event channel.register(selector, SelectionKey.OP_CONNECT); } /** * Listen to whether there are events to be processed on the selector by polling. If there are, process them * * @throws IOException */ private void connect() throws IOException { // Poll access selector while (true) { // Select a group of events that can be used for I/O operations and put them in the selector. The method of the client will not block, // The method here is different from that of the server. Looking at the api annotation, you can see that when at least one channel is selected, // The wakeup method of the selector is called, and the method returns. For the client, the channel is always selected selector.select(); // Get the iterator of the selected item in the selector Iterator<SelectionKey> it = this.selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey key = it.next(); // Delete the selected key to prevent repeated processing it.remove(); // Connection event occurs if (key.isConnectable()) { SocketChannel channel = (SocketChannel) key.channel(); // If you are connecting, complete the connection if (channel.isConnectionPending()) { channel.finishConnect(); } // Set to non blocking channel.configureBlocking(false); // Send a message to the server ByteBuffer buffer = ByteBuffer.wrap("HelloServer".getBytes()); channel.write(buffer); // After the connection with the server is successful, in order to receive the information from the server, you need to set the read permission for the channel. Register OP for this channel_ Read event channel.register(this.selector, SelectionKey.OP_READ); } else if (key.isReadable()) { // Get the Socket channel of the event SocketChannel channel = (SocketChannel) key.channel(); // Create read buffer ByteBuffer buffer = ByteBuffer.allocate(512); int len = channel.read(buffer); if (len != -1) { System.out.println("Client receives message:" + new String(buffer.array(), 0, len)); } } } } } }
summary
The selector of NIO model is like a big manager, which is responsible for listening to various IO events and then handing them over to the back-end thread for processing;
NIO is non blocking compared with BIO in that the back-end thread of BIO needs to block waiting for the client to write data (such as the read method). If the client does not write data, the thread will block. NIO hands over the waiting for the client to operate to the selector. The selector is responsible for polling all registered clients. After listening to an event, it will be handed over to the back-end thread for processing. The back-end thread does not need to do any blocking and waiting. It can directly process the data of the client event. After processing, it will end immediately, or return to the thread pool for other client events to continue to use. Also, the reading and writing of the channel is non blocking.
Redis is a typical NIO threading model. The selector collects all connected events and transfers them to the back-end thread. The thread continuously executes all event commands and writes the results back to the client;
AIO(NIO 2.0)
Asynchronous non blocking. After the operation system completes, the callback notifies the server program to start the thread for processing. It is generally suitable for applications with a large number of connections and a long connection time;
Application scenario
AIO mode is applicable to the architecture with a large number of connections and long connections (re operation), and JDK7 starts to support it;
Code example
Bio&nio&aio comparison
Synchronous & asynchronous
synchronous synchronization is a reliable and orderly operation mechanism. When we synchronize, the subsequent task is to wait for the current call to return before proceeding to the next step.
Asynchronous is the opposite of asynchronous. This task does not need to wait for the current call to return, but realizes the order relationship between tasks by relying on mechanisms such as events and callbacks.
Blocking & non blocking
Blocking: when blocking, the current thread will be in a blocking state and cannot engage in other tasks. It can continue only when the conditions are met, such as the completion of data reading and writing operations.
Non blocking non blocking refers to the direct return of IO operations regardless of whether they are finished, and the corresponding operations continue to be processed in the background.