Netty学习 - 简单的HTTP服务器

Netty有四种核心组件:通道(Channel)、回调(Callback)、Future和事件处理器(Handler),本文以一个简单的HTTP服务器入门介绍这四种组件。本系列使用的Netty版本是4.1.25.Final。

一个简单的HTTP服务器

import java.net.InetSocketAddress;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
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.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;

public class MyHttpServer {
    private static final int MAX_CONTENT_LENGTH = 512 * 1024;

    public static void main(String[] args) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .localAddress(new InetSocketAddress(9999))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast("codec", new HttpServerCodec())
                                    .addLast("aggregator", new HttpObjectAggregator(MAX_CONTENT_LENGTH))
                                    .addLast(new MyHttpServerHandler());
                        }
                    });
            ChannelFuture f = b.bind().sync();
            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully().sync();
            workerGroup.shutdownGracefully().sync();
        }
    }
}

在上述代码中

  1. 首先创建两个EventLoopGroup,其中bossGroup用于监听套接字(主Reactor),workerGroup用于已连接套接字(从Reactor)。为了达到异步的目的,这里选用的是NioEventLoopGroup,其他还有OioEventLoopGroup等。
  2. 然后创建一个ServerBootstrap实例并为其设置属性,group绑定EventLoopGroup,channel指定监听套接字的通道类型,localAddress指定监听地址,childHandler方法指定了如何初始化已连接套接字的通道。我们为已连接套接字通道设置了三个处理器,分别是netty自带的HttpServerCodec和HttpObjectAggregator以及自定义的入站事件处理器MyHttpServerHandler:
    • HttpServerCodec将来自客户端的请求从字节流解码为netty的数据结构,并可将从服务器发出的响应编码为字节流;
    • HttpObjectAggregator将多个分组的HTTP内容聚合成一个;
    • MyHttpServerHandler将打印HTTP请求体的内容,并向客户端发回响应:HTTP版本1.1,状态码200,响应体是字符串“netty server responsed successfully”,可以用Postman或浏览器试验看看效果。
  3. 最后调用bind方法开始监听本地端口9999。
    public class MyHttpServerHandler extends ChannelInboundHandlerAdapter {

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            FullHttpRequest request = (FullHttpRequest) msg;
            ByteBuf buf = request.content();
            System.out.println("body: " + buf.toString(CharsetUtil.UTF_8));
            ctx.writeAndFlush(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
                    Unpooled.copiedBuffer("netty server responsed successfully", CharsetUtil.UTF_8)))
                    .addListener(ChannelFutureListener.CLOSE);
        }
    }

Netty的核心组件

在上述代码中,我们已经见到了netty的四种组件:通道、回调、Future和事件处理器。

通道

通道(Channel)代表一个到实体(如硬件设备、文件、网络套接字)的开放连接。

回调

Netty在内部使用回调(Callback)来处理事件,当回调被触发时,相关的事件可以被ChannelHandler接口的实现去处理。如对上述代码所示的自定义处理器,当可以从远程节点读取消息时,channelRead回调就会被调用。

Future

Future提供了一种在操作完成时通知应用程序的方式,虽然Java有自己的Future但是Netty提供了自己的Future实现——ChannelFuture。每个Netty的出站I/O操作都将返回一个ChannelFuture,都不会阻塞,完全是异步和事件驱动的。

  • ServerBootstrap调用bind方法后会返回ChannelFuture;
  • 自定义处理器中writeAndFlush会返回ChannelFuture。

事件处理器

Netty是一个网络编程框架,因此事件按照数据流向分类。
入站事件包括:

  • 连接被激活或者失活
  • 数据读取:自定义处理器中响应了这个事件
  • 错误事件
  • 用户事件

出站事件包括:

  • 打开或关闭到远程节点的连接
  • 将数据写到或者冲刷到套接字

事件处理器有两种,入站处理器(ChannelInboundHandler接口及其实现)和出站处理器(ChannelOutboundHandler接口及其实现)。我们可以为一个通道添加多个处理器,它们是按照代码中的顺序被添加到一个通道对应的流水线(ChannelPipeline)上的,入站事件被入站事件处理器处理,出站事件被出站事件处理器处理。以本文代码为例,按照代码顺序,HttpServerCodec是第一个入站处理器,同时也是唯一一个出站处理器;HttpObjectAggregator是第二个入站处理器;MyHttpServerHandler是第三个入站处理器。


IO events.png

参考文献

《Netty实战》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容