netty 簡介
Netty一個基于NIO的客戶、服務器端的編程框架
1.環(huán)境準備
maven依賴
? <dependency>
? ? ? ? ? ? <groupId>io.netty</groupId>
? ? ? ? ? ? <artifactId>netty-all</artifactId>
? ? ? ? ? ? <version>4.1.42.Final</version>
? </dependency>
12345
RequestMethodEnum 請求方式
public enum RequestMethodEnum {
? GET("GET"),
? POST("POST");
? public String code;
? RequestMethodEnum(String code) {
? ? this.code=code;
? }
}
12345678
ParentServlet 父類servlet
public abstract class ParentServlet {
? public void service(ParentRequest request, ParentResponse response) throws Exception {
? ? //service 方法決定調(diào)用doGet、doPost;
? ? if (RequestMethodEnum.GET.code.equalsIgnoreCase(request.getMethod())) {
? ? ? doGet(request, response);
? ? } else {
? ? ? doPost(request, response);
? ? }
? }
? protected abstract void doPost(ParentRequest request, ParentResponse response) throws Exception;
? protected abstract void doGet(ParentRequest request, ParentResponse response) throws Exception;
}
12345678910111213141516
FirstServlet
public class FirstServlet extends ParentServlet {
? @Override
? protected void doPost(ParentRequest request, ParentResponse response) throws Exception {
? ? response.write("This is the first");
? }
? @Override
? protected void doGet(ParentRequest request, ParentResponse response) throws Exception {
? ? this.doPost(request,response);
? }
}
1234567891011
SecondServlet
public class SecondServlet extends ParentServlet {
? @Override
? protected void doPost(ParentRequest request, ParentResponse response) throws Exception {
? ? response.write("this is the second");
? }
? @Override
? protected void doGet(ParentRequest request, ParentResponse response) throws Exception {
? ? this.doPost(request,response);
? }
}
1234567891011
ParentRequest
public class ParentRequest {
? private String method;
? private String url;
? public String getUrl() {
? ? return url;
? }
? public String getMethod() {
? ? return method;
? }
}
1234567891011121314
ParentResponse
public class ParentResponse {
? private OutputStream out;
? public ParentResponse (OutputStream out) {
? ? this.out = out;
? }
? public void write(String s) throws Exception{
? ? //輸出也要遵循HTTP
? ? //狀態(tài)碼為200
? ? StringBuilder sb = new StringBuilder();
? ? sb.append("HTTP/1.1 200 OK \n")
? ? ? .append("Content-Type: text/html;\n")
? ? ? .append("\r\n")
? ? ? .append(s);
? ? out.write(sb.toString().getBytes());
? }
}
1234567891011121314151617
web.properties
servlet.first.url=/first
servlet.first.className=com.aiden.servlet.FirstServlet
servlet.second.url=/second
servlet.second.className=com.aiden.servlet.SecondServlet
1234
2.基于傳統(tǒng)I/O手寫Tomcat
修改ParentRequest
public class ParentRequest {
? private String method;
? private String url;
? public ParentRequest(InputStream in) {
? ? try {
? ? ? String content = "";
? ? ? byte[] buff = new byte[1024];
? ? ? int len = 0;
? ? ? if ((len = in.read(buff)) > 0) {
? ? ? ? content = new String(buff,0,len);
? ? ? }
? ? ? String line = content.split("\\n")[0];
? ? ? String [] arr = line.split("\\s");
? ? ? this.method = arr[0];
? ? ? System.out.println(method);
? ? ? this.url = arr[1].split("\\?")[0];
? ? } catch (IOException e) {
? ? ? e.printStackTrace();
? ? }
? }
? public String getUrl() {
? ? return url;
? }
? public String getMethod() {
? ? return method;
? }
}
12345678910111213141516171819202122232425262728293031
編寫tomcatStart類
public class TomcatStart {
? private int port = 8080;
? private ServerSocket server;
? private Map<String, ParentServlet> servletMapping = new HashMap<String, ParentServlet>();
? private Properties webProperties = new Properties();
? private void init() {
? ? try {
? ? ? String WEB_INF = this.getClass().getResource("/").getPath();
? ? ? FileInputStream fis = new FileInputStream(WEB_INF + "web.properties");
? ? ? webProperties.load(fis);
? ? ? for (Object k : webProperties.keySet()) {
? ? ? ? String key = k.toString();
? ? ? ? if (key.endsWith(".url")) {
? ? ? ? ? String servletName = key.replaceAll("\\.url$", "");
? ? ? ? ? String url = webProperties.getProperty(key);
? ? ? ? ? String className = webProperties.getProperty(servletName + ".className");
? ? ? ? ? //單實例? 多線程
? ? ? ? ? ParentServlet obj = (ParentServlet) Class.forName(className).newInstance();
? ? ? ? ? servletMapping.put(url, obj);
? ? ? ? }
? ? ? }
? ? } catch (Exception e) {
? ? ? e.printStackTrace();
? ? }
? }
? public void start() {
? ? //1.加載配置類,初始化servletMapping
? ? init();
? ? try {
? ? ? //2.綁定端口啟動
? ? ? server = new ServerSocket(this.port);
? ? ? System.out.println("Tomcat 已啟動,監(jiān)聽端口是:" + this.port);
? ? ? //3.等待用戶請求,用一個死循環(huán)
? ? ? while (true) {
? ? ? ? Socket client = server.accept();
? ? ? ? //4.http 請求
? ? ? ? process(client);
? ? ? }
? ? } catch (IOException e) {
? ? ? e.printStackTrace();
? ? }
? }
? private void process(Socket client) throws IOException {
? ? InputStream is = null;
? ? OutputStream os = null;
? ? try {
? ? ? is = client.getInputStream();
? ? ? os = client.getOutputStream();
? ? ? //5.Request(inputstream) Response (outputstream)
? ? ? ParentRequest request = new ParentRequest(is);
? ? ? ParentResponse response = new ParentResponse(os);
? ? ? //6.從協(xié)議內(nèi)容中獲取url 映射相應的servlet
? ? ? String url = request.getUrl();
? ? ? if (servletMapping.containsKey(url)) {
? ? ? ? //7.調(diào)用實例化對象的service方法
? ? ? ? servletMapping.get(url).service(request, response);
? ? ? } else {
? ? ? ? response.write("404 - Not Found");
? ? ? }
? ? } catch (Exception e) {
? ? ? e.printStackTrace();
? ? } finally {
? ? ? if (os != null) {
? ? ? ? os.flush();
? ? ? ? os.close();
? ? ? }
? ? ? if (is != null) {
? ? ? ? is.close();
? ? ? }
? ? ? client.close();
? ? }
? }
? public static void main(String[] args) {
? ? //啟動
? ? new TomcatStart().start();
? }
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
3.基于netty手寫Tomcat
修改ParentRequest
public class ParentRequest {
? private ChannelHandlerContext ctx;
? private HttpRequest req;
? public ParentRequest(ChannelHandlerContext ctx, HttpRequest req) {
? ? this.ctx = ctx;
? ? this.req = req;
? }
? public String getUrl() {
? ? return req.uri();
? }
? public String getMethod() {
? ? return req.method().name();
? }
? public Map<String, List<String>> getParameters() {
? ? QueryStringDecoder decoder = new QueryStringDecoder(req.uri());
? ? return decoder.parameters();
? }
? public String getParameter(String name) {
? ? Map<String, List<String>> params = getParameters();
? ? List<String> param = params.get(name);
? ? if (null == param) {
? ? ? return null;
? ? } else {
? ? ? return param.get(0);
? ? }
? }
}
123456789101112131415161718192021222324252627282930313233
修改ParentResponse
public class ParentResponse {
? //SocketChannel的封裝
? private ChannelHandlerContext ctx;
? private HttpRequest req;
? public ParentResponse(ChannelHandlerContext ctx, HttpRequest req) {
? ? this.ctx = ctx;
? ? this.req = req;
? }
? public void write(String out) throws Exception {
? ? try {
? ? ? if (out == null || out.length() == 0) {
? ? ? ? return;
? ? ? }
? ? ? // 設置 http協(xié)議及請求頭信息
? ? ? FullHttpResponse response = new DefaultFullHttpResponse(
? ? ? ? // 設置http版本為1.1
? ? ? ? HttpVersion.HTTP_1_1,
? ? ? ? // 設置響應狀態(tài)碼
? ? ? ? HttpResponseStatus.OK,
? ? ? ? // 將輸出值寫出 編碼為UTF-8
? ? ? ? Unpooled.wrappedBuffer(out.getBytes("UTF-8")));
? ? ? response.headers().set("Content-Type", "text/html;");
? ? ? ctx.write(response);
? ? } finally {
? ? ? ctx.flush();
? ? ? ctx.close();
? ? }
? }
}
12345678910111213141516171819202122232425262728293031323334
修改TomcatStart
public class TomcatStart {
? private int port = 8080;
? private Map<String, ParentServlet> servletMapping = new HashMap<String, ParentServlet>();
? private Properties webProperties = new Properties();
? private void init() {
? ? try {
? ? ? String WEB_INF = this.getClass().getResource("/").getPath();
? ? ? FileInputStream fis = new FileInputStream(WEB_INF + "web.properties");
? ? ? webProperties.load(fis);
? ? ? for (Object k : webProperties.keySet()) {
? ? ? ? String key = k.toString();
? ? ? ? if (key.endsWith(".url")) {
? ? ? ? ? String servletName = key.replaceAll("\\.url$", "");
? ? ? ? ? String url = webProperties.getProperty(key);
? ? ? ? ? String className = webProperties.getProperty(servletName + ".className");
? ? ? ? ? //單實例? 多線程
? ? ? ? ? ParentServlet obj = (ParentServlet) Class.forName(className).newInstance();
? ? ? ? ? servletMapping.put(url, obj);
? ? ? ? }
? ? ? }
? ? } catch (Exception e) {
? ? ? e.printStackTrace();
? ? }
? }
? public void start() {
? ? //1.加載配置類,初始化servletMapping
? ? init();
? ? // Netty? NIO Reactor模型 Boss Worker
? ? //Boss 線程
? ? EventLoopGroup bossGroup = new NioEventLoopGroup();
? ? //Work線程
? ? EventLoopGroup workGroup = new NioEventLoopGroup();
? ? ServerBootstrap server = null;
? ? try {
? ? ? //創(chuàng)建對象
? ? ? server = new ServerBootstrap();
? ? ? //配置參數(shù)
? ? ? //鏈式編程
? ? ? server.group(bossGroup, workGroup)
? ? ? ? //主線程處理類,
? ? ? ? .channel(NioServerSocketChannel.class)
? ? ? ? //子線程處理類
? ? ? ? .childHandler(new ChannelInitializer<SocketChannel>() {
? ? ? ? ? @Override
? ? ? ? ? protected void initChannel(SocketChannel client) throws Exception {
? ? ? ? ? ? //無鎖化串行編程
? ? ? ? ? ? //netty對http的封裝 對順序有要求
? ? ? ? ? ? //httpResponseEncoder 編碼器
? ? ? ? ? ? client.pipeline().addLast(new HttpResponseEncoder());
? ? ? ? ? ? //httprequestDecoder 解碼器
? ? ? ? ? ? client.pipeline().addLast(new HttpRequestDecoder());
? ? ? ? ? ? //業(yè)務處理器
? ? ? ? ? ? client.pipeline().addLast(new TomcatHandler());
? ? ? ? ? }
? ? ? ? })
? ? ? ? //主線程 線程最大數(shù)量128
? ? ? ? .option(ChannelOption.SO_BACKLOG, 128)
? ? ? ? //子線程配置 保存長連接
? ? ? ? .childOption(ChannelOption.SO_KEEPALIVE, true);
? ? ? ChannelFuture f = server.bind(port).sync();
? ? ? System.out.println("Tomcat 已啟動,監(jiān)聽端口是:" + this.port);
? ? ? f.channel().closeFuture().sync();
? ? } catch (Exception e) {
? ? ? e.printStackTrace();
? ? } finally {
? ? ? bossGroup.shutdownGracefully();
? ? ? workGroup.shutdownGracefully();
? ? }
? }
? public class TomcatHandler extends ChannelInboundHandlerAdapter {
? ? @Override
? ? public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
? ? ? if (msg instanceof HttpRequest) {
? ? ? ? System.out.println("hello request");
? ? ? ? HttpRequest req = (HttpRequest) msg;
? ? ? ? ParentRequest request = new ParentRequest(ctx, req);
? ? ? ? ParentResponse response = new ParentResponse(ctx, req);
? ? ? ? String url = request.getUrl();
? ? ? ? if (servletMapping.containsKey(url)) {
? ? ? ? ? //7.調(diào)用實例化對象的service方法
? ? ? ? ? servletMapping.get(url).service(request, response);
? ? ? ? } else {
? ? ? ? ? response.write("404 - Not Found");
? ? ? ? }
? ? ? }
? ? }
? }
? public static void main(String[] args) {
? ? //啟動
? ? new TomcatStart().start();
? }
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
4.訪問
http://localhost:8080/first