Netty learning: build a simple Netty service
Netty is an asynchronous communication framework based on JAVA NIO class library. Its architectural features are: asynchronous non-blocking, event-driven, high performance, high reliability and high customizability. In other words, Netty is a NIO framework that makes it easy and fast to develop network applications, such as client and server protocols. Netty greatly simplifies the development process of network programs, such as the development of Sockets for TCP and UDP. Netty has gradually become the framework of choice for Java NIO programming.
Project official address: http://netty.io/index.html
1. Advantages of Netty:
- The API is easy to use, and the development threshold is low;
- Powerful, preset a variety of codec functions, support a variety of mainstream protocols;
- Strong customization ability, the communication framework can be flexibly extended through ChannelHandler;
- High performance, compared with other mainstream NIO frameworks in the industry, Netty has the best overall performance;
- The community is active, the version iteration cycle is short, the bugs found can be fixed in time, and more new functions will be added;
- After a large-scale commercial application test, the quality has been verified. It has been successfully commercialized in many industries such as the Internet, big data, online games, enterprise applications, and telecommunication software, which proves that it fully meets the commercial standards of different industries.
2. Build Netty service:
- add pom dependencies
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.0.Final</version> </dependency>
- SimpleServer (server)
package com.yingjun.netty.server; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; /** * * In Netty, after the two parties of the communication establish a connection, the data will be transmitted in the way of ByteBuf. * For example, in the http protocol, the ByteBuf data stream is processed through the HttpRequestDecoder and converted into an http object. * */ public class SimpleServer { private int port; public SimpleServer(int port) { this.port = port; } public void run() throws Exception { //EventLoopGroup is a multi-threaded event looper used to handle IO operations //bossGroup is used to receive incoming connections EventLoopGroup bossGroup = new NioEventLoopGroup(); //workerGroup is used to handle connections that have been received EventLoopGroup workerGroup = new NioEventLoopGroup(); try { //Auxiliary startup class to start NIO service ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) //Configure Channel .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { // register handler ch.pipeline().addLast(new SimpleServerHandler()); } }) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); // Bind the port and start receiving incoming connections ChannelFuture f = b.bind(port).sync(); // Wait for the server socket to close. f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { new SimpleServer(9999).run(); } }
- SimpleServerHandler (server request processing Handler)
package com.yingjun.netty.server; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; public class SimpleServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("SimpleServerHandler.channelRead"); ByteBuf result = (ByteBuf) msg; byte[] result1 = new byte[result.readableBytes()]; // msg stores data of type ByteBuf, and reads the data into byte[] result.readBytes(result1); String resultStr = new String(result1); // Receive and print client information System.out.println("Client said:" + resultStr); // Release resources, this line is critical result.release(); // send message to client String response = "hello client!"; // In the current scenario, the sent data must be converted into a ByteBuf array ByteBuf encoded = ctx.alloc().buffer(4 * response.length()); encoded.writeBytes(response.getBytes()); ctx.write(encoded); ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { // close the connection when an exception occurs cause.printStackTrace(); ctx.close(); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } }
- SimpleServer (client)
package com.yingjun.netty.server; import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; public class SimpleClient { public void connect(String host, int port) throws Exception { EventLoopGroup workerGroup = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(workerGroup); b.channel(NioSocketChannel.class); b.option(ChannelOption.SO_KEEPALIVE, true); b.handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new SimpleClientHandler()); } }); // Start the client. ChannelFuture f = b.connect(host, port).sync(); // Wait until the connection is closed. f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { SimpleClient client=new SimpleClient(); client.connect("127.0.0.1", 9999); } }
- SimpleServerHandler (client request processing Handler)
package com.yingjun.netty.server; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; public class SimpleClientHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("SimpleClientHandler.channelRead"); ByteBuf result = (ByteBuf) msg; byte[] result1 = new byte[result.readableBytes()]; result.readBytes(result1); System.out.println("Server said:" + new String(result1)); result.release(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { // close the connection when an exception occurs cause.printStackTrace(); ctx.close(); } // After the connection is successful, send a message to the server @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { String msg = "hello Server!"; ByteBuf encoded = ctx.alloc().buffer(4 * msg.length()); encoded.writeBytes(msg.getBytes()); ctx.write(encoded); ctx.flush(); } }
- operation result:
SimpleClientHandler.channelRead Server said:hello client! ------------------------------------------ SimpleServerHandler.channelRead Client said:hello Server! SimpleServerHandler.channelRead Client said:hello Server!