当前位置: 首页 > article >正文

【Netty】实战:基于Http的Web服务器

目录

一、实现ChannelHandler 

二、实现ChannelInitializer

三、实现服务器启动程序

四、测试


本文来实现一个简单的Web服务器,当用户在浏览器访问Web服务器时,可以返回响应的内容给用户。很简单,就三步。

一、实现ChannelHandler 

package cn.md.netty.httpserver;

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;

/**
 * * @Author: Martin
 * * @Date    2024/9/1 17:47
 * * @Description
 **/
public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    /**
     * Is called for each message of type {@link I}.
     *
     * @param ctx the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler}
     *            belongs to
     * @param msg the message to handle
     * @throws Exception is thrown if an error occurred
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
        // 打印Http请求
        printHttpRequest(msg);

        String uri = msg.uri();
        String resp;
        switch (uri) {
            case "/":
                resp = "hello world";
                break;
            case "/test":
                resp = "test";
                break;
            case "/hi":
                resp = "hello";
                break;
            default:
                resp = "404";
        }
        // 返回http格式响应
        returnHttpResp(ctx, resp);
    }

    private void returnHttpResp(ChannelHandlerContext ctx, String msg) {
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
                Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8));

        response.headers().set(HttpHeaderNames.CONTENT_LENGTH,msg.length());

        ctx.writeAndFlush(response)
                .addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
    }

    private void printHttpRequest(FullHttpRequest msg) {
        String uri = msg.uri();
        HttpMethod method = msg.method();
        HttpVersion httpVersion = msg.protocolVersion();
        // 打印请求行
        System.out.println("uri:" + uri + " method:" + method + " httpVersion:" + httpVersion);

        HttpHeaders headers = msg.headers();
        for (String name : headers.names()) {
            System.out.println(name + ":" + headers.get(name));
        }

        System.out.println("");
        System.out.println(msg.content().toString(CharsetUtil.UTF_8));
    }
}

二、实现ChannelInitializer

package cn.md.netty.httpserver;

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

/**
 * * @Author: Martin
 * * @Date    2024/9/1 17:55
 * * @Description
 **/
public class HttpServerChannelInitializer extends ChannelInitializer<SocketChannel> {

    /**
     * This method will be called once the {@link Channel} was registered. After the method returns this instance
     * will be removed from the {@link ChannelPipeline} of the {@link Channel}.
     *
     * @param ch the {@link Channel} which was registered.
     * @throws Exception is thrown if an error occurs. In that case it will be handled by
     *                   {@link #exceptionCaught(ChannelHandlerContext, Throwable)} which will by default close
     *                   the {@link Channel}.
     */
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        // 添加自定义的handler
        ch.pipeline().addLast("codec",new HttpServerCodec()) // 添加编解码器
                // 添加聚合器,聚合为一个完整的 FullHttpMessage
                .addLast("aggregator",new HttpObjectAggregator(1024*1024*10))
                .addLast("handler",new HttpServerHandler());
    }
}

三、实现服务器启动程序

package cn.md.netty.httpserver;

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

/**
 * * @Author: Martin
 * * @Date    2024/9/1 18:01
 * * @Description
 **/
public class HttpServer {

    public static void main(String[] args) {

        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        ServerBootstrap serverBootstrap = new ServerBootstrap();

        try {
            ChannelFuture channelFuture = serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new HttpServerChannelInitializer())
                    //服务器在处理客户端连接请求时的等待队列长度。
                    //当服务器接收到客户端的连接请求时,如果服务器正在处理其他连接或者处于忙碌状态,新的连接请求将被放入等待队列中。
                    .option(ChannelOption.SO_BACKLOG, 128)
                    //底层套接字级别设置的选项,由操作系统的 TCP/IP 协议栈实现保活机制。
                    //当开启后,在一定时间没有数据传输时,操作系统自动发送保活探测报文来检测连接是否仍然有效。
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .bind(8888)
                    .sync();


            channelFuture.channel().closeFuture().sync();

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }

    }

}

四、测试

 


我是马丁,如果你喜欢,麻烦点个赞~ 下期见~


http://www.kler.cn/a/288490.html

相关文章:

  • 【专题】计算机网络之网络层
  • flink sql + kafka + mysql 如何构建实时数仓
  • Lucene 和 Elasticsearch 中更好的二进制量化 (BBQ)
  • AtomicInteger 和 AtomicIntegerFieldUpdater的区别
  • scrapy爬取中信证券销售金融产品信息
  • 计算机毕业设计必看必学35755flask旅游景区热度可视化平台原创定制程序,java、PHP、python、小程序、文案全套、毕设成品等
  • 数据分析及应用:如何分析基于绝对中位差的异常值检测问题?
  • LINUX网络编程:Tcpsocket封装
  • Java GC机制:Minor GC与Full GC的触发条件
  • 假期作业--数据结构
  • uniapp插槽用法
  • vue子组件样式影响父组件
  • 每天一个数据分析题(五百一十六)- 贝叶斯分类算法
  • Axure打造科技感数据可视化大屏原型
  • 网络安全宗旨和目标
  • OpenCV颜色空间转换(1)颜色空间转换函数cvtColor()的使用
  • 【论文阅读】skill code 和 one-shot manipulate
  • C++ 设计模式——职责链模式
  • Go父类调用子类方法(虚函数调用)
  • stm32之I2C通信外设
  • 提升RAG检索回答质量: Shortwave的 4 大优化指南
  • 使用 Milvus Lite、Llama3 和 LlamaIndex 搭建 RAG 应用
  • 住宅IP与机房IP:哪种更适合业务应用?
  • 51单片机-第十节-独立按键及数码管优化
  • shell脚本—————局域网IP扫描
  • 开放式耳机漏音有多大?五大超值爆款推荐!