1, Related introduction
(1) Synchronous blocking mode (Blocking IO)
1. Traditional blocking communication process
The early Java network related API(java.net package) used socket (socket) for network communication, but only supported the use of blocking functions.
To communicate over the Internet, at least one pair of sockets is required:
- The Server Socket running on the server side.
- The Client Socket running on the client side.
2.Socket network communication process
In short, it is divided into the following four steps:
- Establishing a server and listening to client requests;
- The client requests, and the server establishes a connection with the client;
- Data can be transferred between two ends;
- Close the resource.
Server side:
- Create a ServerSocket object and bind the address (ip) and port number (port): server bind(new InetSocketAddress(host, port));
- Listen for client requests through the accept() method;
- After the connection is established, read the request information sent by the client through the input stream;
- Close related resources
client:
- Create a Socket object and connect the address (ip) and port number (port) of the specified server: Socket connect(inetSocketAddress);
- After the connection is established, send request information to the server through output;
- Obtaining the information of the server response through the input stream;
- Close related resources
3. Synchronous blocking model (BIO)
The synchronous blocking IO model is the simplest IO model. When the user thread performs IO operations in the kernel, if the data is not ready, it will be blocked. The blocking mode BIO in Java is in Java Net package. Socket socket socket is the implementation of TCP/UDP and other transport layer protocols.
BIO features:
- One thread is responsible for connection, and multiple threads open one thread for each access;
- One request and one response;
- After a request, the client waits (blocks) until it answers.
(2) Synchronous non blocking model (non blocking IO)
NIO is a synchronous non blocking I/O model. NIO framework is introduced in Java 1.4, corresponding to Java NIO package provides abstractions such as channel, selector and Buffer. NIO supports Buffer oriented and channel based I/O operation methods.
Characteristics of NIO
NIO provides two different Socket channel implementations of SocketChannel and ServerSocketChannel corresponding to Socket and ServerSocket in the traditional BIO model. Both channels support blocking and non blocking modes:
- Blocking mode: basically not used. It is just like the traditional network programming, which is relatively simple, but the performance and reliability are not good. For low load and low concurrency applications, you can barely use it to improve development speed and better maintainability;
- Non blocking mode: Contrary to blocking mode, non blocking mode is very friendly for high load and high concurrency (Network) applications, but programming is troublesome, which is criticized by most people. Therefore, it led to the birth of Netty.
(3) Netty
Introduction to Netty
- Netty is a NIO based client server framework, which can be used to develop network applications quickly and easily.
It greatly simplifies and simplifies network programming such as TCP and UDP socket server, and has even better performance and security. - It supports a variety of protocols, such as FTP, SMTP, HTTP and various binary and text-based traditional protocols.
- The official conclusion is that Netty has successfully found a way to achieve ease of development, performance, stability and flexibility without compromising maintainability and performance.
Netty features
- Unified API, supporting multiple transmission types, blocking and non blocking;
- Simple and powerful thread model;
- The built-in codec solves the problem of TCP packet sticking / unpacking;
- With various protocol stacks;
- True connectionless packet socket support;
- It has higher throughput, lower latency, lower resource consumption and less memory replication than using Java core API directly;
- Good security, complete SSL/TLS and StartTLS support;
- Active community;
- Mature and stable, it has experienced the use and test of large projects, and many open source projects use Netty, such as Dubbo, RocketMQ and so on.
Netty's role
- As a network communication tool of RPC framework;
- Implement your own HTTP server;
- Implement an instant messaging system;
- Message push system.
2, IO instance
1. Create a new server
Create a new Java class server
import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; public class server { public static void main(String[] args) throws IOException { //Create the Socket object of the client (seversocket) //ServerSocket (int port) creates a server socket bound to a specified port ServerSocket ss=new ServerSocket(50000); //Socket accept() listens to connect to this socket and accepts it Socket s=ss.accept(); //Get the input stream, read the data, and display the data on the console InputStream is=s.getInputStream(); byte[] bys=new byte[1024]; int len=is.read(bys); String data=new String(bys,0,len); System.out.println("The data are:"+data); //Release resources s.close(); ss.close(); } }
As shown below
2. Create a new client
The steps are the same as above. Change the name of the new project to IOclient and the class name to client
As shown below
Compile and run both server and client
give the result as follows
3, NIO instance
Server side
Change the name to NIOserver and the code is as follows
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; import java.util.Set; public class NIOserver { //Network communication, IO operation, TCP protocol, optional channel for stream oriented listening socket (generally used for server) private ServerSocketChannel serverSocketChannel; private Selector selector; /* *Open the server */ public void start(Integer port) throws Exception { serverSocketChannel = ServerSocketChannel.open(); selector = Selector.open(); //Binding listening port serverSocketChannel.socket().bind(new InetSocketAddress(port)); //Set to non blocking mode serverSocketChannel.configureBlocking(false); //Register on Selector serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); startListener(); } private void startListener() throws Exception { while (true) { // If the client has a method to request select, the return value will not be zero if (selector.select(1000) == 0) { System.out.println("current not exists task"); continue; } // If there is an event set, the key of the corresponding channel exists Set<SelectionKey> selectionKeys = selector.selectedKeys(); Iterator<SelectionKey> iterator = selectionKeys.iterator(); // Traverse all keys to find the key with the event type of Accept while (iterator.hasNext()) { SelectionKey key = iterator.next(); if (key.isAcceptable()) handleConnection(); if (key.isReadable()) handleMsg(key); iterator.remove(); } } } /** * Process connection establishment */ private void handleConnection() throws Exception { SocketChannel socketChannel = serverSocketChannel.accept(); socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024)); } /* * Receive information */ private void handleMsg(SelectionKey key) throws Exception { SocketChannel channel = (SocketChannel) key.channel(); ByteBuffer attachment = (ByteBuffer) key.attachment(); channel.read(attachment); System.out.println("current msg: " + new String(attachment.array())); } public static void main(String[] args) throws Exception { NIOserver myServer = new NIOserver(); myServer.start(8888); } }
As shown below
client
Change the name to NIO and the code is as follows
import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; public class NIOclient { public static void main(String[] args) throws Exception { SocketChannel socketChannel = SocketChannel.open(); socketChannel.configureBlocking(false); // Connect server if (!socketChannel.connect(new InetSocketAddress("127.0.0.1", 8888))) { while (!socketChannel.finishConnect()) { System.out.println("connecting..."); } } //send data String str = "hello netty"; ByteBuffer byteBuffer = ByteBuffer.wrap(str.getBytes()); socketChannel.write(byteBuffer); System.in.read(); } }
As shown below
Compile and run at the same time
4, Netty instance
Server side
Renamed Nettyserver
Import Netty framework dependencies
Enter io Netty: netty all to search
The code is as follows:
import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import java.net.InetSocketAddress; /** * */ public class Nettyserver { private int port; public static void main(String[] args){ new Nettyserver(18080).start(); } public Nettyserver(int port) { this.port = port; } public void start() { /** * Create two eventloopgroups, that is, two thread pools. The boss thread pool is used to receive client connections, * A thread listens to one port. Generally, it only listens to one port, so only one thread is required * work The pool is used to process network connection data reading and writing or subsequent business processing (another thread can be specified to process business, * work Complete data reading and writing) */ EventLoopGroup boss = new NioEventLoopGroup(1); EventLoopGroup work = new NioEventLoopGroup(); try { /** * Instantiate a server startup class, * group()Specify thread group * channel()Specifies the class used to receive client connections, corresponding to Java nio. ServerSocketChannel * childHandler()Sets the class for encoding, decoding and processing connections */ ServerBootstrap server = new ServerBootstrap() .group(boss, work).channel(NioServerSocketChannel.class) .localAddress(new InetSocketAddress(port)) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline() .addLast("decoder", new StringDecoder()) .addLast("encoder", new StringEncoder()) .addLast(new HelloWorldServerHandler()); } }); //Binding port ChannelFuture future = server.bind().sync(); System.out.println("server started and listen " + port); future.channel().closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); }finally { boss.shutdownGracefully(); work.shutdownGracefully(); } } public static class HelloWorldServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println("HelloWorldServerHandler active"); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("server channelRead.."); System.out.println(ctx.channel().remoteAddress()+"->Server :"+ msg.toString()); ctx.write("server write"+msg); ctx.flush(); } } }
As shown below
Server
Change the name to Nettyclient, and the steps of package import are the same
The code is as follows
import io.netty.bootstrap.Bootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; /** * */ public class Nettyclient { private static final String HOST = "localhost"; private static final int PORT= 18080; public static void main(String[] args){ new Nettyclient().start(HOST, PORT); } public void start(String host, int port) { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap client = new Bootstrap().group(group).channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true).handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline() .addLast("decoder", new StringDecoder()) .addLast("encoder", new StringEncoder()) .addLast(new HelloWorldClientHandler()); } }); ChannelFuture future = client.connect(host, port).sync(); future.channel().writeAndFlush("Hello Netty Server ,I am a netty client"); future.channel().closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); } finally { group.shutdownGracefully(); } } public static class HelloWorldClientHandler extends ChannelInboundHandlerAdapter { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println("HelloWorldClientHandler Active"); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("HelloWorldClientHandler read Message:"+msg); } } }
As shown below
Compile and run at the same time
reference resources
From BIO and NIO to Netty, we need to implement an RPC framework!
TCP chat program based on IO, NIO and Netty