netty搭建http服务器:Netty学习-简单的HTTP服务器
netty搭建http服务器:Netty学习-简单的HTTP服务器Future提供了一种在操作完成时通知应用程序的方式,虽然Java有自己的Future但是Netty提供了自己的Future实现——ChannelFuture。每个Netty的出站I/O操作都将返回一个ChannelFuture,都不会阻塞,完全是异步和事件驱动的。Future通道(Channel)代表一个到实体(如硬件设备、文件、网络套接字)的开放连接。回调Netty在内部使用回调(Callback)来处理事件,当回调被触发时,相关的事件可以被ChannelHandler接口的实现去处理。如对上述代码所示的自定义处理器,当可以从远程节点读取消息时,channelRead回调就会被调用。
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(); } } }
在上述代码中
- 首先创建两个EventLoopGroup,其中bossGroup用于监听套接字(主Reactor),workerGroup用于已连接套接字(从Reactor)。为了达到异步的目的,这里选用的是NioEventLoopGroup,其他还有OioEventLoopGroup等。
- 然后创建一个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或浏览器试验看看效果。
- 最后调用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是第三个入站处理器。