netty學習一:用netty構造http服務的小demo
阿新 • • 發佈:2019-02-15
概述
netty可以支援http、socket、websocket,本文會做一個小demo,簡單介紹一下如何用netty搭建一個http服務。
netty雖然可以提供http服務,但是相比spring mvc、struts2等框架,netty顯得比較底層,很多spring mvc提供的功能,netty統統都沒有。
步驟
編寫netty程式的步驟都比較相似:
1、 啟動group監聽客戶端請求
2、編寫Initializer新增handler
3、自定義業務handler
啟動group監聽客戶端請求
package http;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class HttpServer {
public static void main(String[] args) throws InterruptedException {
// 接收連線,但是不處理
EventLoopGroup parentGroup = new NioEventLoopGroup();
// 真正處理連線的group
EventLoopGroup childGroup = new NioEventLoopGroup();
try {
//載入Initializer
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(parentGroup, childGroup)
.channel(NioServerSocketChannel.class)
//這裡的childHandler是服務於childGroup的,如果直接使用
//handler方法新增處理器,則是服務於parentGroup的
.childHandler(new HttpServerInitializer());
//繫結監聽埠
ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
channelFuture.channel().closeFuture().sync();
}
finally {
parentGroup.shutdownGracefully();
childGroup.shutdownGracefully();
}
}
}
EventLoopGroup類似死迴圈,一直監聽8899埠是否有請求到達。
編寫Initializer新增handler
package http;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
public class HttpServerInitializer extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//處理http服務的關鍵handler
pipeline.addLast("httpServerCodec",new HttpServerCodec());
//自定義的handler
pipeline.addLast("testHttpServerHandler",new HttpServerHandler());
}
}
自定義業務handler
package http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.CharsetUtil;
public class HttpServerHandler extends SimpleChannelInboundHandler<HttpObject>{
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
if (msg instanceof HttpRequest) {
HttpRequest httpRequest = (HttpRequest)msg;
System.out.println("請求方法名稱:"+httpRequest.method().name());
System.out.println("請求來自:"+ctx.channel().remoteAddress());
ByteBuf content = Unpooled.copiedBuffer("Hello World!",CharsetUtil.UTF_8);
DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.OK,
content);
response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH,content.readableBytes());
ctx.writeAndFlush(response);
ctx.channel().close();
}
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("handler add");
super.handlerAdded(ctx);
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel registed");
super.channelRegistered(ctx);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel active");
super.channelActive(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel inactive");
super.channelInactive(ctx);
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel unregisted");
super.channelUnregistered(ctx);
}
}
測試
執行main方法啟動netty http程式,並使用curl命令測試。
輸出結果如下:
handler add
channel registed
channel active
請求方法名稱:GET
請求來自:/0:0:0:0:0:0:0:1:52291
channel inactive
channel unregisted
csdn code 路徑
這個專案的原始碼放置在csdn code上,歡迎訪問。