这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战
今天来搭建一个Netty Http Server,闲话少说,开战吧!
本篇使用IDEA + Maven搭建,
第一步,修改pom文件
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.67.Final</version>
</dependency>
</dependencies>
第二步:创建HttpServer
- 在这一步中,我们构造了两个线程组BossGroup和WorkerGroup,作用是什么呢?
- bossGroup与workGroup都是一个独立的Reactor
- bossGroup是负责接收请求,Reactor的优势是一个线程能处理多个请求,核心是通过for循环实现
- workGroup负责不同连接的读写请求,使用轮询的方式,一旦有接收到数据,则创建线程执行 所以,这两者是分工明确的运行着,bossGroup负责连接,workGroup负责处理I/O请求
/**
* @version 1.0
* @date 2021/8/29 20:43
*/
public class HttpServer {
//定义服务端的端口号
int port = 8080;
public void start() throws Exception{
//构造两个线程组:BossGroup和WorkerGroup
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//服务端启动辅助类,配置NioEventLoopGroup
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new HttpServerInitializer());
ChannelFuture future = bootstrap.bind(port).sync();
System.out.println(" server start up on port : " + port);
//等待服务端口关闭
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
// 优雅退出,释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
第三步:定义HttpServerInitializer
自定义一个类 HttpServerInitializer 继承 ChannelInitializer 并实现其中的 initChannel方法, 当一个新的连接被接受时, 一个新的 Channel 将被创建,同时它会被自动地分配到它专属的 ChannelPipeline 自定义的ChannelHandler主要作用是处理业务逻辑
/**
* @version 1.0
* @date 2021/8/29 20:44
*/
public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
ChannelPipeline pipeline = sc.pipeline();
//处理http消息的编解码
pipeline.addLast("httpServerCodec", new HttpServerCodec());
pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
//添加自定义的ChannelHandler
pipeline.addLast("httpServerHandler", new HttpServerChannelHandler());
}
}
第四部:自定义ChannelHandler(关键点)
/**
* @version 1.0
* @date 2021/8/29 20:53
*/
public class HttpServerChannelHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
ctx.channel().remoteAddress();
FullHttpRequest request = msg;
System.out.println("请求方法名称:" + request.method().name());
System.out.println("请求的uri:" + request.uri());
System.out.println("HTTP协议版本:" + request.getProtocolVersion().text());
ByteBuf buf = request.content();
System.out.print(buf.toString(CharsetUtil.UTF_8));
ByteBuf byteBuf = Unpooled.copiedBuffer("Received message successfully", CharsetUtil.UTF_8);
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf);
response.headers().add(HttpHeaderNames.CONTENT_TYPE, "text/plain");
response.headers().add(HttpHeaderNames.CONTENT_LENGTH, byteBuf.readableBytes());
ctx.writeAndFlush(response);
}
}
HTTP请求发送中,Netty HTTP Server收到的请求数据
其中,FullHttpRequest f有以下的方法:
- f.getMethod.name()//获取请求方法
- f.getMethod.getUri()//获取请求的url
- f.getProtocolVersion().text()//获取
- f.headers().get("Content-Type");// 获取header中的数据,这里是map格式
最后,在执行HttpServer的start方法
客户端测试
使用 Postman postman这个工具模拟客户端来测试, 发起调用GET请求:http://localhost:8080 以及成功收到反馈的消息:Received message successfully
今日小结 今天搭建的Http服务器算是入门级别的,主要目的是能够直观的感受到Netty的使用