http 服务器(Netty学习)

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回调就会被调用。FutureFuture提供了一种在操作完成时通知应用程序的方式,虽然Java有自己的Future但是Netty提供了自己的Future实现——ChannelFuture。每个Netty的出站I/O操作都将返回一个ChannelFuture,都不会阻塞,完全是异步和事件驱动的。ServerBootstrap调用bind方法后会返回ChannelFuture;自定义处理器中writeAndFlush会返回ChannelFuture。事件处理器Netty是一个网络编程框架,因此事件按照数据流向分类。 入站事件包括:连接被激活或者失活数据读取:自定义处理器中响应了这个事件错误事件用户事件出站事件包括:打开或关闭到远程节点的连接将数据写到或者冲刷到套接字事件处理器有两种,入站处理器(ChannelInboundHandler接口及其实现)和出站处理器(ChannelOutboundHandler接口及其实现)。我们可以为一个通道添加多个处理器,它们是按照代码中的顺序被添加到一个通道对应的流水线(ChannelPipeline)上的,入站事件被入站事件处理器处理,出站事件被出站事件处理器处理。以本文代码为例,按照代码顺序,HttpServerCodec是第一个入站处理器,同时也是唯一一个出站处理器;HttpObjectAggregator是第二个入站处理器;MyHttpServerHandler是第三个入站处理器。

本文出自快速备案,转载时请注明出处及相应链接。

本文永久链接: https://www.175ku.com/26821.html