本文使用netty自定義了一個http協議的服務器。
1.創建一個maven項目,在pom.xml文件中導入依賴並刷新
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.16.Final</version>
</dependency>
2.搭建一個Netty服務器,我們只需要兩個類——一個是啓動類,負責啓動(BootStrap)和main方法;一個是ChannelHandler,負責具體的業務邏輯。
啓動類:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
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.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import java.util.Date;
/**
* Created by RoyDeng on 20/03/22.
*/
public class HttpServer {
private final static int port = 8080;
public static void main(String[] args) throws Exception {
System.out.println(new Date().toLocaleString()+"netty服務器啓動了");
start();
}
public static void start() throws Exception {
//ServerBootstrap作爲一個啓動輔助類,通過他可以很方便的創建一個Netty服務端
ServerBootstrap b = new ServerBootstrap();
//創建線程池
NioEventLoopGroup group = new NioEventLoopGroup();
b.group(group)
//指定使用NioServerSocketChannel來處理連接請求,放射生成一個channel連接
.channel(NioServerSocketChannel.class)
//配置handler和childHandler,數據處理器
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch)
throws Exception {
System.out.println("initChannel ch:" + ch);
ch.pipeline()
// HttpRequestDecoder,用於解碼request
.addLast("decoder", new HttpRequestDecoder())
// HttpResponseEncoder,用於編碼response
.addLast("encoder", new HttpResponseEncoder())
//aggregator消息聚合器,參數含義是消息合併的數據大小,如此代表聚合的消息內容長度不超過512kb
.addLast("aggregator", new HttpObjectAggregator(512 * 1024))
//添加我們自己的處理接口
.addLast("handler", new HttpHandler()); // 4
}
})
.option(ChannelOption.SO_BACKLOG, 128) // 配置TCP參數
.childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE);//
//啓動服務器
b.bind(port).sync();
}
}
handler線程處理類
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.AsciiString;
import java.util.Date;
/**
* Handler需要聲明泛型爲<FullHttpRequest>,聲明之後,只有msg爲FullHttpRequest的消息才能進來
*/
public class HttpHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
private AsciiString contentType = HttpHeaderValues.TEXT_PLAIN;
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
System.out.println(new Date().toLocaleString()+"class:" + msg.getClass().getName());
/*
生成response,使用的FullHttpResponse,同FullHttpRequest類似,
通過這個我們就不用將response拆分成多個channel返回給請求端了
*/
DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.OK,
// 響應內容:test --> 使用平臺的默認字符集將字符串編碼爲 byte 序列,存爲新的 byte 數組中
Unpooled.wrappedBuffer("test".getBytes()));
HttpHeaders heads = response.headers();
//定義響應頭的content_type、content_length、connection:keep_alive
heads.add(HttpHeaderNames.CONTENT_TYPE, contentType + "; charset=UTF-8");
heads.add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); // 3
heads.add(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
ctx.write(response);
}
//讀取完成,輸出緩衝流
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println(new Date().toLocaleString()+"channelReadComplete");
super.channelReadComplete(ctx);
//清空連接數據
ctx.flush();
}
//異常捕獲
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("exceptionCaught");
if(null != cause) cause.printStackTrace();
if(null != ctx) ctx.close();
}
}
運行,瀏覽器輸入:http://localhost:8080