从零学Netty(六)Netty实现Http服务器

朱雀 2022-12-14 12:24 376阅读 0赞

简介

  • HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写
  • HTTP是一个基于TCP/IP通信协议来传递数据

工作原理

  • HTTP协议工作于C/S架构上,浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求
  • Web服务器根据接收到的请求后,向客户端发送响应信息
  • HTTP默认端口号为80,但是你也可以改为8080或者其他端口
  • HTTP是无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
  • HTTP是媒体独立的:这意味着,只要客户端和服务器知道如何处理的数据内容,任何类型的数据都可以通过HTTP发送。客户端以及服务器指定使用适合的MIME-type内容类型。
  • HTTP是无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

编写Http Servlet规范类

Servlet抽象类

  1. /**
  2. * Servlet
  3. *
  4. * @author LionLi
  5. */
  6. public abstract class Servlet {
  7. public abstract void doGet(Request request,Response response);
  8. public abstract void doPost(Request request,Response response);
  9. }

Request相关功能实现

  1. /**
  2. * Request
  3. *
  4. * @author LionLi
  5. */
  6. public class Request {
  7. private ChannelHandlerContext ctx;
  8. private HttpRequest r;
  9. public Request(ChannelHandlerContext ctx, HttpRequest r) {
  10. this.ctx = ctx;
  11. this.r = r;
  12. }
  13. public String getUri() {
  14. return r.uri();
  15. }
  16. public String getMethod() {
  17. return r.method().name();
  18. }
  19. public Map<String, List<String>> getParameters() {
  20. QueryStringDecoder decoder = new QueryStringDecoder(r.uri());
  21. return decoder.parameters();
  22. }
  23. public String getParameter(String name) {
  24. Map<String, List<String>> params = getParameters();
  25. List<String> param = params.get(name);
  26. if (null == param) {
  27. return null;
  28. } else {
  29. return param.get(0);
  30. }
  31. }
  32. }

Response相关功能实现

  1. /**
  2. * Response
  3. *
  4. * @author LionLi
  5. */
  6. public class Response {
  7. private ChannelHandlerContext ctx;
  8. private HttpRequest r;
  9. public Response(ChannelHandlerContext ctx, HttpRequest r) {
  10. this.ctx = ctx;
  11. this.r = r;
  12. }
  13. public void write(String out) throws Exception {
  14. try {
  15. if (out == null || out.length() == 0) {
  16. return;
  17. }
  18. // 设置 http协议及请求头信息
  19. FullHttpResponse response = new DefaultFullHttpResponse(
  20. // 设置http版本为1.1
  21. HttpVersion.HTTP_1_1,
  22. // 设置响应状态码
  23. HttpResponseStatus.OK,
  24. // 将输出值写出 编码为UTF-8
  25. Unpooled.wrappedBuffer(out.getBytes("UTF-8")));
  26. // 设置连接类型 为 JSON
  27. response.headers().set(CONTENT_TYPE, "text/json");
  28. // 设置请求头长度
  29. response.headers().set(CONTENT_LANGUAGE, response.content().readableBytes());
  30. // 设置超时时间为5000ms
  31. response.headers().set(EXPIRES, 5000);
  32. // 当前是否支持长连接
  33. // if (HttpUtil.isKeepAlive(r)) {
  34. // // 设置连接内容为长连接
  35. // response.headers().set(CONNECTION, HttpHeaderValues.KEEP_ALIVE);
  36. // }
  37. ctx.write(response);
  38. } finally {
  39. ctx.flush();
  40. ctx.close();
  41. }
  42. }
  43. }

自定义Servlet处理

  1. /**
  2. * servlet处理
  3. *
  4. * @author LionLi
  5. */
  6. public class MyServlet extends Servlet {
  7. public void doGet(Request request, Response response) {
  8. try {
  9. // 获取 name 参数 并返回
  10. response.write(request.getParameter("name"));
  11. } catch (Exception e) {
  12. e.printStackTrace();
  13. }
  14. }
  15. public void doPost(Request request, Response response) {
  16. doGet(request,response);
  17. }
  18. }

编写Server相关类

http服务器主类

  1. /**
  2. * http服务器
  3. *
  4. * @author LionLi
  5. */
  6. public class HttpServer {
  7. public void start(int port) throws Exception {
  8. // Boss线程
  9. EventLoopGroup bossGroup = new NioEventLoopGroup();
  10. // Worker线程
  11. EventLoopGroup workerGroup = new NioEventLoopGroup();
  12. try {
  13. ServerBootstrap server = new ServerBootstrap();
  14. server.group(bossGroup, workerGroup)
  15. // 主线程处理类
  16. .channel(NioServerSocketChannel.class)
  17. // 子线程处理类
  18. .childHandler(new ChannelInitializer<SocketChannel>() {
  19. // 客户端初始化处理
  20. protected void initChannel(SocketChannel client) {
  21. // HttpResponseEncoder 编码器
  22. client.pipeline().addLast(new HttpResponseEncoder());
  23. // HttpRequestDecoder 解码器
  24. client.pipeline().addLast(new HttpRequestDecoder());
  25. // 业务逻辑处理
  26. client.pipeline().addLast(new HttpHandler());
  27. }
  28. })
  29. // 针对主线程的配置 分配线程最大数量 128
  30. .option(ChannelOption.SO_BACKLOG, 128)
  31. // 针对子线程的配置 保持长连接
  32. .childOption(ChannelOption.SO_KEEPALIVE, true);
  33. // 启动服务器 sync 同步阻塞
  34. ChannelFuture f = server.bind(port).sync();
  35. System.out.println("HttpServer Startd Port: " + port);
  36. f.channel().closeFuture().sync();
  37. } finally {
  38. // 关闭线程池
  39. bossGroup.shutdownGracefully();
  40. workerGroup.shutdownGracefully();
  41. }
  42. }
  43. public static void main(String[] args) {
  44. try {
  45. new HttpServer().start(8088);
  46. } catch (Exception e) {
  47. e.printStackTrace();
  48. }
  49. }
  50. }

业务处理Handler类

  1. /**
  2. * 业务处理
  3. *
  4. * @author LionLi
  5. */
  6. public class HttpHandler extends ChannelInboundHandlerAdapter {
  7. @Override
  8. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  9. if (msg instanceof HttpRequest){
  10. HttpRequest r = (HttpRequest) msg;
  11. Request request = new Request(ctx,r);
  12. Response response = new Response(ctx,r);
  13. MyServlet.class.newInstance().doGet(request,response);
  14. }
  15. }
  16. @Override
  17. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  18. }
  19. }

测试

启动HttpServer

2020101317134613.png

启动成功无异常

访问netty服务器 http://localhost:8088/?name=LionLi

20201013171420751.png

成功返回结果

项目已上传到gitee

地址: netty-demo

如果帮到您了,请帮忙点个star

发表评论

表情:
评论列表 (有 0 条评论,376人围观)

还没有评论,来说两句吧...

相关阅读

    相关 开始netty

    Netty概述: 1、netty是基于Java NIO的网络应用框架,client-server框架 2、Netty是一个高性能、异步事件驱动的NIO框架,它提供了对T