IO of JAVA IO – API
Network IO programming steps
NIO
- Create a listener that allows a client to initiate a request
- After binding network Socket ports, an important step is to check whether services need to be set to block the OS
- Accept () in an infinite loop
- Read the data
public class ServerNIO { public static void main(String[] args) { ServerNIO nio = new ServerNIO(); ServerSocketChannel socketChannel = nio.inintServer(); while (true){ nio.getMsg(socketChannel); Private ServerSocketChannel inintServer(){ServerSocketChannel Server = null; Try {//NIO Channel create listener server = serverSocketChannel.open (); // Bind port 9999 server.bind(new InetSocketAddress(9999)); // Set OS NONBLOCKING server.configureBlocking(false); System.out.println(" Server started "); } catch (IOException e) { e.printStackTrace(); } return server; } private void getMsg(ServerSocketChannel ServerSocketChannel){try {// The server receives requests from the client SocketChannel client = serverSocketChannel.accept(); if (client ! =null){// Set client to a non-blocking client.configureBlocking(false); / / optimize performance increase buffer ByteBuffer buffer = ByteBuffer. AllocateDirect (2048); Int read = client.read(buffer); If (read>0){// Switch the read/write mode buffer.flip(); byte[] aaa = new byte[buffer.limit()]; buffer.get(aaa); String b = new String(aaa); System.out.println(client.socket().getPort() + " : " + b); buffer.clear(); } } } catch (IOException e) { e.printStackTrace(); }}}Copy the code
The key to multiplexing is the introduction of the Selector selector, which processes I/O requests in batches
package nio; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.*; import java.util.Iterator; import java.util.Set; /** * @Classname SocketMultiplexingSingleThread * @Description TODO * @Date 2020/12/23 10:34 AM * @Author by lixin */ public class SocketMultiplexingSingleThread { private ServerSocketChannel server =null; private Selector selector=null; Private void initServer(){try {// Create channel listener server =ServerSocketChannel.open(); // Bind port 8888 server.bind(new InetSocketAddress(8888)); // Set OS NONBLOCKING server.configureBlocking(false); Epoll_create ->fd */ selector = poll_create ->fd */ selector = Selector.open(); // The server registers with the multiplexer and declares events. /* select * from the JVM, poll: Epoll_ctl (fd3,ADD,fd4,EPOLLIN,EPOLLIN, epoll_ctl) creates two more spatial red black trees (all epoll_ctl commands store FD in the tree) and statically linked list result set */ server.register(selector, SelectionKey.OP_ACCEPT); } catch (IOException e) { e.printStackTrace(); } } public void getMsg() throws IOException { initServer(); System.out.println(" Server started "); While (true){// Loop to see if any messages come in /* 1. Selector. Select () (which increases the blocking time) Poll select (fd) poll(fd) */ while (selector. Select ()>0){// Retrieve all events from selector /* */ Set<SelectionKey> keys = selectedKeys(); */ Set<SelectionKey> keys = selector. Iterator<SelectionKey> iterator = keys.iterator(); while (iterator.hasNext()){ SelectionKey key = iterator.next(); // **** events that are processed need to be removed. If they are not removed, they will be processed in a loop. **** iterator.remove(); If (key.isacceptable ()){if (key.isacceptable ()){if (key.isacceptable ()){if (key.isacceptable ()){if (key.isacceptable ()){if (key.isacceptable ()){if (key.isacceptable ()){if (key.isacceptable ()){ We register acceptHandler(key) in the kernel space with epoll_ctl; }else if (key.isreadable ()){// Note that read is often blocked for various things, such as a minute, an hour, or even a year, so that the system cannot be used by others. IO Threads the same idea is present in Redis. Redis has the concept of readHandler(key) for IO Threads because it is a single thread. } //... }}}} private void readHandler(SelectionKey key) {// Read data from client SocketChannel client = (SocketChannel) key.channel(); // client.register(selector,SelectionKey.OP_READ,buffer); //ByteBuffer buffer = (ByteBuffer) key.attachment(); Buffer = (ByteBuffer) key.attachment(); // Pairs of buffers are registered with the selector and read with attachment(). buffer.clear(); int read= 0; try { while (true){ read = client.read(buffer); if (read>0){ buffer.flip(); while (buffer.hasRemaining()) { client.write(buffer); } buffer.clear(); }else if (read == 0) { break; } else { client.close(); break; } } } catch (IOException e) { e.printStackTrace(); }} private void acceptHandler(SelectionKey key) {// Obtain the ServerSocketChannel ServerSocketChannel = (ServerSocketChannel) key.channel(); Try {/ / from the server receives the new client SocketChannel client = serverSocketChannel. The accept (); client.configureBlocking(false); ByteBuffer buffer = ByteBuffer.allocate(8192); Register (selector, selectionkey. OP_READ,buffer); System.out.println("-------------------------------------------"); System.out.println(" new client: "+ client.getremoteAddress ()); System.out.println("-------------------------------------------"); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) throws IOException { SocketMultiplexingSingleThread sevice = new SocketMultiplexingSingleThread(); sevice.getMsg(); }}Copy the code
Extreme version of multiplexing elite API, to tell you about the idea
- In order to take full advantage of the multi-core CPU, we can keep the CPU as busy as possible. The ideal number of threads is the number of CPU cores or twice the number of CPU cores
- We can use multiple threads, create multiple selectors, one for each thread
- We can mix to handle events, or we can specify a selector to handle only receiving clients
- Another selector handles W/R events, and this idea is very close to Netty and if we could write it out by hand it would give us a good foundation for netty later on