Netty(1) 实现 Http 服务器
App.java
package org.example;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
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.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import java.net.InetSocketAddress;
/**
* Hello world!
*/
public class App {
int port;
public App(int port) {
this.port = port;
}
public static void start(Integer port) throws InterruptedException {
ServerBootstrap bootstrap = new ServerBootstrap();
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup work = new NioEventLoopGroup();
bootstrap.group(boss, work)
.handler(new LoggingHandler(LogLevel.DEBUG))
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new HttpServerInitializer());
}
});
ChannelFuture f = bootstrap.bind(new InetSocketAddress(port)).sync();
System.out.println(" server start up on port : " + port);
f.channel().closeFuture().sync();
}
public static void main(String[] args) {
try {
start(8080);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
这个函数是一个静态方法,命名为 start,接收一个 Integer 类型的参数 port。函数的目的是启动一个基于 NIO 的服务器。 首先,函数创建了一个 ServerBootstrap 对象,并为它创建了两个 EventLoopGroup 对象,分别用于 boss 线程和工作线程。 然后,通过调用 bootstrap 的 group 方法将 boss 和 work 对象设置为 EventLoopGroup 对象。 接下来,使用 LoggingHandler 作为处理器来设置 socket 的调试日志级别为 DEBUG。 然后,通过调用 bootstrap 的 channel 方法设置服务器通道类为 NioServerSocketChannel。 最后,通过调用 bootstrap 的 bind 方法将服务器绑定到给定的 InetSocketAddress 对象,并调用 sync 方法等待绑定操作完成。 紧接着,函数打印一条消息,显示服务器成功启动在给定的端口上。 最后,通过调用 closeFuture 的 sync 方法等待通道关闭操作完成,结束函数执行。
Socket 通道初始化
package org.example;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new HttpServerCodec());// http 编解码
pipeline.addLast("httpAggregator",new HttpObjectAggregator(512*1024)); // http 消息聚合器 512*1024为接收的最大contentlength
pipeline.addLast(new HttpRequestHandler());// 请求处理器
}
}
这个函数是一个继承自 Netty 的 ChannelInitializer 类的 Java 类,用于初始化一个 SocketChannel 的管道,其中包括 http 编解码器、http 消息聚合器和请求处理器。
Http 处理器
package org.example;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import java.util.HashMap;
import java.util.Map;
import static io.netty.handler.codec.http.HttpUtil.is100ContinueExpected;
public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
//100 Continue
if (is100ContinueExpected(req)) {
ctx.write(new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1,
HttpResponseStatus.CONTINUE));
}
// 获取请求的uri
String uri = req.uri();
Map<String,String> resMap = new HashMap<>();
resMap.put("method",req.method().name());
resMap.put("uri",uri);
String msg = "<title>你访问的uri是:"+uri+"</title>";
// 创建http响应
FullHttpResponse response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1,
HttpResponseStatus.OK,
Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8));
// 设置头信息
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
//response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
// 将html write到客户端
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}
}
这个函数是一个重写的方法,用于处理通道中的 HTTP 请求。首先,它会检查是否期望一个 100 Continue 的响应,并发送该响应。然后,它获取请求的 URI,并将请求方法和 URI 放入一个字典中。接下来,它根据 URI 创建一个包含 HTML 内容的响应,并设置响应头信息。最后,它将响应写入客户端并关闭连接。这样,客户端就会收到一个包含 URI 信息的 HTML 响应,并且连接会被关闭。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于