IO overview
The core of software development is data, and the transmission, storage and reading of data are realized through IO technology.
There are three main IO models in Java:
- BIO synchronous blocking IO
- NIO synchronous non blocking IO
- AIO asynchronous non blocking IO
BIO
Blocking IO synchronous blocking IO is a commonly used IO model
Characterized by
- Writing is relatively simple
- It is divided into input stream and output stream
- During network communication, the read operation of the input stream will block the thread until an output stream performs write operation
Once the thread of the server is blocked, the server cannot handle the business of other clients. In order to solve this problem, we usually start the thread separately for each client.
This creates a new problem, that is, if there are many clients, it will consume a lot of thread resources of the server, resulting in excessive pressure on the server.
Therefore, this model is more suitable for the situation that the number of connections is small and the number is relatively fixed.
The following is how to use the Socket of BIO model for network communication
/** * BIO The server */ public class SocketServer { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(9000); while (true) { System.out.println("Waiting for connection.."); //Blocking method Socket socket = serverSocket.accept(); System.out.println("A client is connected.."); //Start thread processing client IO new Thread(new Runnable() { @Override public void run() { try { handler(socket); } catch (IOException e) { e.printStackTrace(); } } }).start(); } } /** * Process client IO * @param socket * @throws IOException */ 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. . "); //Receive data from the client and block when there is no data readable int read = socket.getInputStream().read(bytes); if (read != -1) { System.out.println("Data received from client:" + new String(bytes, 0, read)); } //Return data to the client socket.getOutputStream().write("Hello, client".getBytes()); socket.getOutputStream().flush(); } }
/** * client */ public class SocketClient { public static void main(String[] args) throws IOException { Socket socket = new Socket("127.0.0.1", 9000); //Send data to the server socket.getOutputStream().write("Hello!!".getBytes()); socket.getOutputStream().flush(); System.out.println("End of sending data to the server"); byte[] bytes = new byte[1024]; //Receive the data returned by the server socket.getInputStream().read(bytes); System.out.println("Data received from the server:" + new String(bytes)); socket.close(); } }
NIO
jdk1.4. NIO (Noblocking IO synchronous non blocking IO) appears. Different from BIO, NIO will not block threads when reading
NIO has three core components:
- Channel channel is similar to the function of BIO input / output stream. The channel with different IO streams can complete read and write operations at the same time
- Buffer buffer, similar to byte array in BIO, is used to store data
- Selector multiplexer. Each Channel will be registered with the selector. The selector will poll among multiple channels. Once a read-write event occurs, it will be processed immediately
Advantages: a single thread can handle a large number of IO requests, which greatly reduces the pressure on the server.
Disadvantages: if the processing time of each IO request is relatively long, there will be a long queue; Programming is also complex.
It is more suitable for dealing with scenes with a large number of connections and a short time, such as chat, bullet screen, etc.
The 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(); //It must be configured as non blocking to register with the selector ssc.configureBlocking(false); ssc.socket().bind(new InetSocketAddress(9000)); // Create selector Selector selector = Selector.open(); // Register on the selector and be interested in client connection operation ssc.register(selector, SelectionKey.OP_ACCEPT); while (true) { // Polling the key in the listening channel. select is blocked selector.select(); System.out.println("Event occurrence"); // 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 key s processed this time to prevent repeated processing in the next select it.remove(); handle(key); } } } /** * event processing * @param key * @throws IOException */ private static void handle(SelectionKey key) throws IOException { //Handling connection events if (key.isAcceptable()) { System.out.println("Handling connection events"); //Get ServerSocketChannel ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); //Get the client received by ServerSocketChannel SocketChannel sc = ssc.accept(); sc.configureBlocking(false); //Register interested in SocketChannel read events sc.register(key.selector(), SelectionKey.OP_READ); } //Handle read events else if (key.isReadable()) { System.out.println("Handle read events"); SocketChannel sc = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); //The read method will not block. The event that the client sends data must have occurred when calling 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("Hello client".getBytes()); sc.write(bufferToWrite); key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); } //Handle write events else if (key.isWritable()) { SocketChannel sc = (SocketChannel) key.channel(); System.out.println("Handle write events"); key.interestOps(SelectionKey.OP_READ); } } }
client
public class NIOClient { //Multiplexer 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", 9000); client.connect(); } /** * Initialize the Socket and do some work on the channel * * @param ip ip address of the connected server * @param port The port number of the connected server * @throws IOException */ public void initClient(String ip, int port) throws IOException { // Obtain 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 implementation of the method does not realize the connection. It needs to be adjusted in the listen () method. //Use channel Finishconnect() to complete the connection channel.connect(new InetSocketAddress(ip, port)); //Bind the channel manager to the channel and register the selectionkey for the channel OP_ Connect event. channel.register(selector, SelectionKey.OP_CONNECT); } /** * Use polling to monitor whether there are events to be processed on the selector. If so, process them * * @throws IOException */ public void connect() throws IOException { // Polling access selector while (true) { selector.select(); // Gets the iterator of the selected item in the selector Iterator<SelectionKey> it = this.selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey key = (SelectionKey) 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); //You can send information to the server here 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. channel.register(this.selector, SelectionKey.OP_READ); // Get readable events } else if (key.isReadable()) { read(key); } } } } /** * Handle the event of reading the information sent by the server * * @param key * @throws IOException */ public void read(SelectionKey key) throws IOException { //It is the same as the read method of the server // Socket: get the message that the server can read SocketChannel channel = (SocketChannel) key.channel(); // Create read buffer ByteBuffer buffer = ByteBuffer.allocate(1024); int len = channel.read(buffer); if (len != -1) { System.out.println("Client received message:" + new String(buffer.array(), 0, len)); } } }
AIO
AIO (asynchronous non blocking), after the operating system completes, the callback notifies the server program to start the thread for processing
It is suitable for operation with a large number of connections and a long time. Jdk1 7 start
The server
public class AIOServer { public static void main(String[] args) throws Exception { //Open the asynchronous server channel and bind the port final AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(9000)); //Set the server to receive connection callback serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() { //Connection successful @Override public void completed(AsynchronousSocketChannel socketChannel, Object attachment) { try { // Receive client connections serverChannel.accept(attachment, this); System.out.println(socketChannel.getRemoteAddress()); ByteBuffer buffer = ByteBuffer.allocate(1024); //Set callback for reading client data socketChannel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() { //Read successful @Override public void completed(Integer result, ByteBuffer buffer) { buffer.flip(); System.out.println(new String(buffer.array(), 0, result)); socketChannel.write(ByteBuffer.wrap("HelloClient".getBytes())); } @Override public void failed(Throwable exc, ByteBuffer buffer) { exc.printStackTrace(); } }); } catch (IOException e) { e.printStackTrace(); } } //connection failed @Override public void failed(Throwable exc, Object attachment) { exc.printStackTrace(); } }); Thread.sleep(Integer.MAX_VALUE); } }
client
public class AIOClient { public static void main(String[] args) throws Exception { AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open(); socketChannel.connect(new InetSocketAddress("127.0.0.1", 9000)).get(); socketChannel.write(ByteBuffer.wrap("HelloServer".getBytes())); ByteBuffer buffer = ByteBuffer.allocate(512); Integer len = socketChannel.read(buffer).get(); if (len != -1) { System.out.println("Client received message:" + new String(buffer.array(), 0, len)); } } }
Comparison of BIO, NIO and AIO
BIO | NIO | AIO | |
---|---|---|---|
IO model | Synchronous blocking | Synchronous non blocking | Asynchronous blocking |
Programming difficulty | Lower | higher | higher |
reliability | difference | good | good |
throughput | low | high | high |
Take chestnuts for example: go to the restaurant for dinner and wait for a seat
BIO: wait in line at the door after getting the number and do nothing
NIO: after taking the number, go shopping next to it and come to see if you can see it at regular intervals
AIO: after making a reservation on your mobile phone, go shopping next to it, and then go there after you notice on your mobile phone