Netty implements a simple http server

Since the client is a browser, only the server needs to be written

Server: bind port 10086

package com.jym.http;

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

/**
 * @program: NettyPro
 * @description: Server side, simple implementation of http
 * @author: jym
 * @create: 2020/02/08
 */
public class TestSever {
    public static void main(String[] args) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new TestSeverInitializer());

            ChannelFuture channelFuture = serverBootstrap.bind(10086).sync();

            channelFuture.addListener(new ChannelFutureListener() {
                public void operationComplete(ChannelFuture channelFuture)  {
                    if(channelFuture.isSuccess()){
                        System.out.println("Listening port 10086 succeeded");
                    } else {
                        System.out.println("Listening port failed");
                    }
                }
            });
            channelFuture.channel().closeFuture().sync();

        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }
}

Custom Initializer needs to inherit ChannelInitializer override method:

package com.jym.http;

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

/**
 * @program: NettyPro
 * @description:
 * @author: jym
 * @create: 2020/02/08
 */
public class TestSeverInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        // Add processor to pipe
        //Get pipe
        ChannelPipeline pipeline = socketChannel.pipeline();
        // Join an httpServer codec provided by netty
        // HttpServerCodec description
        // 1. An http codec provided by netty
        pipeline.addLast("JymHttpSeverCodec",new HttpServerCodec());
        // Add custom processor
        pipeline.addLast("JymHttpSeverHandler",new TestHttpSeverHandler());
    }

}

Customize the handler, because the browser will send two requests, a normal request and a web page icon, which should be handled separately

package com.jym.http;

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.*;
import io.netty.util.CharsetUtil;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;

/**
 * @program: NettyPro
 * @description: Processor, simplechannellinboundhandler Description:
 * 1.Is a subclass of ChannelInboundHandlerAdapter
 * 2.HttpObject The data that the client and server communicate with each other is encapsulated as HttpObject
 * @author: jym
 * @create: 2020/02/08
 */
public class TestHttpSeverHandler extends SimpleChannelInboundHandler<HttpObject> {

    private static byte[] bytes;

    static {
        File file = new File("D:\\wallpaper\\LOL\\1.jpg");
        FileInputStream fi = null;
        try {
            long fileSize = file.length();
            if (fileSize > Integer.MAX_VALUE) {
                throw new IOException(file.getName()+"file too big... ");
            }
            fi = new FileInputStream(file);
            bytes = new byte[(int) fileSize];
            int offset = 0;
            int numRead = 0;
            while (offset < bytes.length
                    && (numRead = fi.read(bytes, offset, bytes.length - offset)) >= 0) {
                offset += numRead;
            }
            // Ensure all data is read
            if (offset != bytes.length) {
                throw new IOException("Could not completely read file "
                        + file.getName());
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fi!=null){
                try {
                    fi.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * Read client data
     */
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {
        // Determine whether httpObject is an HttpRequest request
        if(httpObject instanceof HttpRequest){
            System.out.println("msg Type:"+ httpObject.getClass());
            System.out.println("Client address:"+channelHandlerContext.channel().remoteAddress());

            HttpRequest request = (HttpRequest)httpObject;
            URI uri = new URI(request.uri());
            ByteBuf content = null;
            // Processing Icon
            if("/favicon.ico".equals(uri.getPath())){
                content = Unpooled.copiedBuffer(bytes);
            } else {
                // Reply to browser
                content = Unpooled.copiedBuffer("hello,I am the server", CharsetUtil.UTF_8);
            }
            // Construct an httpResponse
            DefaultFullHttpResponse response =
                    new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,content);
            // Set response header
            response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
            response.headers().set(HttpHeaderNames.CONTENT_LENGTH,content.readableBytes());

            channelHandlerContext.writeAndFlush(response);
        }
    }

}

Simplechannellinboundhandler Description:
1. A subclass of ChannelInboundHandlerAdapter
2. The data that HttpObject client and server communicate with each other is encapsulated as HttpObject

Test results:

After starting the server, access port 10086:

Icons and contents can be displayed normally

Lack of years of study, knowledge is too shallow, please forgive me for saying wrong.

There are 10 kinds of people in the world, one is binary, the other is not binary.

71 original articles published, 54 praised, 420000 visitors+
Private letter follow

Tags: Netty Java codec socket

Posted on Sat, 08 Feb 2020 10:05:08 -0500 by fross