基于Netty实现一个HTTP服务器_netty 实现http服务器
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
一、序言
Netty因其易编程高可靠性高性能的网络IO在分布式开发中被广泛用于网络通信比如RocketMQDubbo底层都能看到Netty的身影高性能的本质是其Reactor线程模型以及异步的编程处理。Reactor有三种模型常用的有主从 Reactor多线程模式具体表现如下
在日常开发中常见基于Netty实现TCP报文传输本文则基于Netty实现一个HTTP服务器了解Netty的另一种用法。跟Nginx类似Netty在HTTP协议栈上也有优越的性能表现不需要依赖Web容器所以相比的Tomcat、Jetty等Web容器会更轻量和轻巧。
二、具体实现
新建一个Pom工程引入Netty的相关依赖
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.42.Final</version>
</dependency>
定义Netty服务端NettyHttpServer用作HTTP服务端。创建bossGroup线程组和workerGroup线程组bossGroup线程组分配一个线程用于轮询注册的通道监听网络的连接事件workerGroup用于处理网络的读写IO事件不指定线程数则默认是CPU核数*2
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
同时定义服务启动助手ServerBootstrap用于管理bossGroup和workerGroup设置服务端通道实现为NIO全连接队列的大小为1024同时增加心跳检测的配置具体代码如下
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE)
.childHandler()
接着初始化通道同时向pipeline中添加自定义的处理的handler针对HTTP请求Netty给我们提供了核心的HTTP编解码器HttpServerCodec所以在通道初始化的时候增加HTTP编解码器同时还有我们自定义的业务处理handler具体代码如下
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new HttpServerCodec());
// 自定义的业务处理handler
ch.pipeline().addLast(new NettyHttpServerHandler());
}
});
之后启动服务端并绑定端口同时将异步改为同步之后监听通道关闭的状态和关闭连接池服务端完整代码如下
public class NettyHttpServer {
private int port;
public NettyHttpServer(int port) {
this.port = port;
}
public void run() throws InterruptedException {
EventLoopGroup bossGroup = null;
EventLoopGroup workerGroup = null;
try {
bossGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new HttpServerCodec());
ch.pipeline().addLast(new NettyHttpServerHandler());
}
});
// 将异步改为同步
ChannelFuture future = serverBootstrap.bind(port);
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
System.out.println("端口" + port + "绑定成功!");
}
}
});
future.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
new NettyHttpServer(8080).run();
}
}
剩下就是定义业务处理handlerNettyHttpServerHandler继承抽象类SimpleChannelInboundHandler用于接收数据的传入类型为HttpObject。当服务端接收到HTTP的请求后回一个响应”Hello! 我是Netty服务器“具体代码如下
public class NettyHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
//1.判断请求是不是HTTP请求
if (msg instanceof HttpRequest) {
DefaultHttpRequest request = (DefaultHttpRequest) msg;
if ("/favicon.ico".equals(request.uri())) {
return;
}
//2.给浏览器进行响应
ByteBuf byteBuf = Unpooled.copiedBuffer("Hello! 我是Netty服务器 ", CharsetUtil.UTF_8);
DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf);
//2.1 设置响应头
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html;charset=utf-8");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, byteBuf.readableBytes());
ctx.writeAndFlush(response);
}
}
}
三、实现效果
启动服务端显示端口绑定成功则说明服务端正常
流量器请求指定端口可以看到在浏览器页面显示服务端返回的数据。
到这里就完成基于Netty实现一个HTTP服务端主要还是依赖于HTTP的编解码器HttpServerCodec用于处理浏览器的GET请求如果要实现POST请求则需要依赖HttpObjectAggregator编解码器。