Using netty to build a simple http server

Keywords: Netty codec Maven network

Article directory

netty overview

Netty is a network programming framework based on java NIO encapsulation, which can help us develop network applications conveniently and quickly. For example, the famous dubbo framework is RPC remote service call based on netty. Netty encapsulates most of the underlying operations of NIO, so we need to have a certain understanding of NIO to better grasp the netty framework.
   java NIO adopts synchronous non blocking technology. Compared with traditional BIO (synchronous blocking), it can handle more requests and make better use of CPU resources (a thread can handle multiple requests, while a BIO thread can only handle one). Synchronous block: when you cut your hair, you always stand on the edge waiting for the barber to cut the previous customer's hair and do nothing. Synchronous block: when you cut your hair, you first do your own things and come back from time to time to see if it's your turn.
                            . It sounds very nice, but unfortunately it has not been widely used, because the read and write operations are handed over to the operating system for processing, and the processing speed largely depends on the stability of the operating system and the quality of the kernel, so NIO is still the mainstream. netty is an excellent network programming framework based on NIO.
Someone will ask why netty is needed now that NIO is available? This is like why spring MVC is needed now that Servlet is available, and why spring boot is needed now that spring MVC is available. The operation of native NIO is more complex, and various mechanisms cause headache, which makes us unable to fully focus on the business requirements. Netty is to solve this problem. Let's take a look at the overall architecture model of netty.

netty architecture model

The architecture model of   netty is further modified and optimized based on the master-slave Reactor multi-threaded model, which has evolved into the overall architecture model as shown in the figure below:

   as shown in the figure above, when a client sends a request, BossGroup is mainly responsible for the Accept connection, and WorkerGroup is responsible for distributing tasks to different handlers. Each handler handles specific business logic. It should be noted that almost all operations in netty are asynchronous, so operations that want to get its specific status can be defined by addListener Implement the method monitoring. NioEventLoop is similar to the selector in NIO, and will always be in a loop.

Manually rolling an http server

                       .

Introducing netty into pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>netty</groupId>
    <artifactId>nettyDemo</artifactId>
    <version>1.0-SNAPSHOT</version>


    <dependencies>
        <!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.20.Final</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>utf-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Write netty server

package nettyhttp;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class TestServer {

    public static void main(String[] args) throws Exception {
        //Create BossGroup and workerGroup
        //bossGroup handles connection requests
        //workerGroup handles client business
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();


        try {

            //Startup class
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            //Set server parameters
            serverBootstrap.group(bossGroup, workerGroup)//Set up team
                    .channel(NioServerSocketChannel.class)//Setup channel
                    .childHandler(new TestServerInitializer());//Set up processor

            System.out.println("server is ready");

            ChannelFuture channelFuture = serverBootstrap.bind(9090).sync();//Binding port
            channelFuture.channel().closeFuture().sync();//Asynchronous monitoring

        } finally {
        	//Error closing connection gracefully
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

}

package nettyhttp;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;


public class TestServerInitializer extends ChannelInitializer<SocketChannel>{
	/**
	* Initialize pipeline
	*/
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        //Get pipe
        ChannelPipeline pipeline = ch.pipeline();
        //HTTP codec provided by netty
        pipeline.addLast("myHttpServerCodec",new HttpServerCodec());
        //Add custom processor
        pipeline.addLast("myHttpServerHandler",new TestHttpServerHandler());
    }

}

package nettyhttp;


import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.CharsetUtil;

import java.net.URI;

public class TestHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {

    /**
     * Read client data
     *
     * @param ctx context
     * @param msg information
     * @throws Exception abnormal
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {

        if (msg instanceof HttpRequest) {
            System.out.println("Client address: " + ctx.channel().remoteAddress());

            HttpRequest httpRequest = (HttpRequest) msg;

            URI uri = new URI(httpRequest.uri());
            if ("/favicon.ico".equals(uri.getPath())) {
                System.out.println("favicon.ico");
                return;
            }

            //Reply to browser
            ByteBuf content = Unpooled.copiedBuffer("hello´╝îI am the server", CharsetUtil.UTF_8);
            //Construct http response
            DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content);

            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain;charset=UTF-8");
            response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());

            ctx.writeAndFlush(response);
        }

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}

                                      Up, as follows:

Operation test

Start the server as follows and print out "server is ready":

   use a browser to access http://localhost:9090, as follows:

   view console:

   the reason why the server prints out the client address twice is that the browser accesses it twice. f12 look at the browser network:

                         ! Here a simple http server is built.

Summary

                             . This blog explains some basic theoretical knowledge of netty and shows the usage of netty through an extremely simple demo. Maybe you have a feeling of To develop their own communication protocol, according to the actual business needs to customize a more suitable network application for the project, so that the project is more robust, with higher performance. There is no end to learning. I'd like to share with you!

26 original articles published, 98 praised, 10000 visitors+
Private letter follow

Posted by dubhcat on Mon, 13 Jan 2020 01:36:59 -0800