1.NIO programming
1.1 what is NIO programming
One understanding is New I/O, because compared with the previous I/O class library, it is new. More people like to call it non block I/O. since non block I/O can better reflect the characteristics of NIO, subsequent NIO refers to non block I/O
1.2 introduction to NiO class library
1. Buffer
In flow oriented I/O In, you can write or read data directly to Stream Object, in NIO In the library, all data is processed with buffers. When writing data, it is also written to the buffer.
Buffer is essentially an array, usually a byte array. Buffer provides structured access to data and maintains read-write limit and other information
2. channel
The difference between channel and flow is that channel is bidirectional, and flow knowledge moves in one direction (a flow must be InputStream perhaps OutputStream And channels can be used for reading, writing, or both. because CHannel It is double full-service, so it better maps the underlying operating system than stream API. Especially in UNIX In the network programming model, the underlying operating systems are full duplex and support read-write operations at the same time. Channel It can be divided into two categories: for network reading and writing SelectableChannel And for file operations FileChannel. ServerSocket and SocketChannel All SelectableChannel Subclass of.
3. Multiplexer Selector
The multiplexer provides the ability to select tasks that are ready. In short, Selector It will register on it continuously Channel,If one Channel There are read or write events on it. This Channel Will be ready and will be Selector Poll out
4. Examples of NiO client and NIO server
public class NioClient { public static void client() throws IOException { // Get channel SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898)); FileChannel inChannel = FileChannel.open(Paths.get("C:\\Users\\renyun\\Desktop\\picture\\logo2.png"), StandardOpenOption.READ); // Allocates a buffer of the specified size ByteBuffer buf = ByteBuffer.allocate(1024); // Read the local file and send it to the server while (inChannel.read(buf) != -1) { // Switch to read data mode buf.flip(); // Writes data from the buffer to the pipeline sChannel.write(buf); // Empty buffer buf.clear(); } //Close channel inChannel.close(); sChannel.close(); } public static void main(String[] args) { new Thread(() -> { try { server(); } catch (IOException e) { e.printStackTrace(); } }, "t1").start(); try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() -> { try { client(); } catch (IOException e) { e.printStackTrace(); } }, "t2").start(); } }
public class NioServer { /** * Server */ public static void server() throws IOException { // Get channel ServerSocketChannel ssChannel = ServerSocketChannel.open(); FileChannel fileChannel = FileChannel.open(Paths.get("C:\\Users\\renyun\\Desktop\\picture\\logo2.png"), StandardOpenOption.WRITE, StandardOpenOption.CREATE); // Binding port number ssChannel.bind(new InetSocketAddress(9898)); // Get the channel of client connection SocketChannel socketChannel = ssChannel.accept(); // Allocates a buffer of the specified size ByteBuffer buf = ByteBuffer.allocate(1024); // Read the data of the client and save it locally while(socketChannel.read(buf) != -1) { // Switch to read mode buf.flip(); // write in fileChannel.write(buf); // Empty buffer buf.clear(); } // Close channel ssChannel.close(); socketChannel.close(); fileChannel.close(); } }
5 why not choose native NIO programming
1.NIO's class libraries and API s are complicated and troublesome to use
2. You need to have other additional skills, such as being familiar with multithreading programming. NIO involves Reactor mode, so you must be very familiar with multithreading and network programming.
3. I can't afford to be happy. The workload and difficulty are very large
4. There is a bug in JDK NiO
2 Netty NIO Getting Started Guide
There are two versions of Netty4 and Netty. It's best to choose Netty4. The first step is to build the project. You can directly reference Maven's dependent package, or directly uninstall the jar package and copy it to the lib directory.
<!--netty rely on--> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.20.Final</version> </dependency> </dependencies>
2.1 netty entry server development
public class NettyServer { public static void main(String[] args) throws InterruptedException { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup worker = new NioEventLoopGroup(); ServerBootstrap bootstrap = new ServerBootstrap(); try { bootstrap.group(bossGroup, worker) //Set up two thread groups .channel(NioServerSocketChannel.class) //Channel implementation as a server .option(ChannelOption.SO_BACKLOG,128) //Set the number of thread queues waiting for connections .childOption(ChannelOption.SO_KEEPALIVE,true) //Set keep active connection status .childHandler(new ChannelInitializer<SocketChannel>() { //Create a channel initialization object //Set up the processor for pipline @Override protected void initChannel(SocketChannel channel) throws Exception { channel.pipeline().addLast(new NettyServerHandler()); } }); // System.out.println("The server is ready"); //Bind a port and synchronize it to generate a ChannelFuture object ChannelFuture cf = bootstrap.bind(6668).sync(); //Listen for closed channels asynchronous model channelFuture cf.channel().closeFuture().sync(); }finally { bossGroup.shutdownGracefully(); worker.shutdownGracefully(); } } }
Introduce key classes
NioEventLoopGroup is specially used for processing network events. In fact, it is the reactor thread group. Two reasons are created: one is for the server to accept the connection of the client, and the other is for the network reading and writing of SocketChannel.
ServerBootstrap is an auxiliary startup class used by Netty to start the server. In order to reduce the development complexity of the server, call the group method and pass the two thread groups to ServerBootstrap as input parameters
ServerSocketChannel class in JDK NIO class library corresponding to NioServerSocketChannel
public class NettyServerHandler extends ChannelInboundHandlerAdapter { //Read data actual (read client message) ChannelHandlerContext context object // The message sent by the Object msg client is in the form of object by default @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("server ctx ="+ctx); ByteBuf buf = (ByteBuf) msg; System.out.println("Send message to client"+buf.toString(CharsetUtil.UTF_8)); System.out.println("Client address"+ctx.channel().remoteAddress()); // super.channelRead(ctx, msg); //Convert msg to bytebuffer } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.writeAndFlush(Unpooled.copiedBuffer("hello client",CharsetUtil.UTF_8)); } //Handle exceptions, usually by closing the channel @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.close(); // super.exceptionCaught(ctx, cause); } }
NettyServerHandler inherits from ChannelInboundHandlerAdapter and reads and writes network events;
Focus on channelRead and exceptionguess methods.
ByteBuf buf = (ByteBuf) msg; Convert msg to Netty's bytebuf object. The bytebuf method can get the number of bytes of the buffer
As can be seen from the above code, compared with the service side of the traditional JDK NIO native class library, the amount of code and development are greatly reduced.
2.2 netty client development
public class NettyClient { public static void main(String[] args) throws InterruptedException { //The client needs only one event loop group EventLoopGroup eventExecutors = new NioEventLoopGroup(); try{ //Create client startup object Bootstrap bootstrap = new Bootstrap(); bootstrap.group(eventExecutors) .channel(NioSocketChannel.class) //Set the processing of client channel .handler(new ChannelInitializer<SocketChannel>() { //Create a channel initialization object //Set up the processor for pipline @Override protected void initChannel(SocketChannel channel) throws Exception { channel.pipeline().addLast(new NettyClientHandler()); } }); System.out.println("The client is ready"); ChannelFuture cf = bootstrap.connect("127.0.0.1", 6668).sync(); cf.channel().closeFuture().sync(); }finally { eventExecutors.shutdownGracefully(); } } }
public class NettyClientHandler extends ChannelInboundHandlerAdapter { //This method is triggered when the channel is ready @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println("client" +ctx); ctx.writeAndFlush(Unpooled.copiedBuffer("HELLO SERVER", CharsetUtil.UTF_8)); } //Triggered when the channel has a read event @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf buf = (ByteBuf) msg; System.out.println("Messages replied by the server"+buf.toString(CharsetUtil.UTF_8)); System.out.println("Server side address"+ctx.channel().remoteAddress()); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }
The service of the client is simpler than that of the server;
Commissioning and operation
It should be noted that this routine does not consider the processing of reading half package, and there is no problem with function demonstration or test. However, if the stress test is carried out, it will not work normally, and the knowledge points related to half package need to be processed. Some methods are used to solve TCP packet sticking and unpacking.