前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >简单web服务器的实现思路

简单web服务器的实现思路

作者头像
只喝牛奶的杀手
发布2019-08-26 16:58:53
1.3K0
发布2019-08-26 16:58:53
举报

回想一下一个http请求的过程,你在浏览器输入xxx.com,经过域名解析 --> 发起tcp的3次握手 --> 建立tcp连接后发起http请求 --> 服务器响应http请求,浏览器得到html代码 --> 浏览器解析html代码,并请求html代码中的资源(如js、css、图片等) --> 浏览器对页面进行渲染呈现给用户。

每一个web服务器程序都需要从网络接受http请求,然后提供http回复给请求者。http回复一般包含一个html文件,有时也可以包含纯文本文件、图像或其他类型的文件。

画外音:web服务器就是一个处理http请求的应用程序。

实现大致步骤:

  • 初始化服务端ServerSocket
  • 初始化TreadPool
  • while(true)等待客户端连接
  • <<服务器启动完成>>
  • 客户端请求
  • clientHandler处理客户端的请求
  • 线程池的线程处理handler
  • 根据输入流解析请求(解析请求行,解析消息头,解析消息正文)
  • 根据输出流创建响应对象(发送状态行信息,发送响应头信息,发送响应正文信息)
  • <<静态html处理结束>>
  • 寻找servlet 根据请求路径找到需要哪个servlet处理(选择handler)
  • 通过反射机制加载这个类
  • 实例化servlet
  • servlet处理请求(执行handler结束)
  • <<跳转html处理结束>>

一个应用程序是不是先要启动起来?main函数当然要有,init方法当然有,我们先不管高性能之类的东西,多路复用Reactor之类的,但是总的有处理并发能力吧,线程池大小默认处理器的核心数,多的也处理不过来!服务器通信归根结底都是socket通信,包括redis服务器都是底层都是socket通信。我们怎么知道http请求来了,先长轮询。

代码语言:javascript
复制
private ServerSocket server;
private ExecutorService threadPool;
public WebServer() {
    try {
        System.out.println("init server begin");
        server = new ServerSocket(8080);
        int poolSize = Runtime.getRuntime().availableProcessors();
        threadPool = newFixedThreadPool(poolSize - 1);
        System.out.println("init server end");
        } catch (Exception e) {
          e.printStackTrace();
        }
    }

public void start() {
    try {
        while (true) {
            //TODO
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) {
    WebServer server = new WebServer();
    server.start();
}

http请求来了,怎么处理?当然需要有定义handler去处理。

代码语言:javascript
复制
 Socket socket = server.accept();
 ClientHandler handler = new ClientHandler(socket);
 threadPool.execute(handler);

handler处理客户端请求并完成响应:

代码语言:javascript
复制
private class ClientHandler implements Runnable {
    private Socket socket;

    public ClientHandler(Socket socket) {
        this.socket = socket;
     }

     public void run() {
         try {
             //根据输入流解析请求
             HttpRequest request= new HttpRequest(socket.getInputStream());
             //先判断用户请求的是否为后端请求
             if (ServerContext.servletMapping.containsKey(
                     request.getRequestLine())
             ) {
                 //通过反射机制加载这个类
                 //实例化这个Servlet
              } else {
                    //查看请求的该页面是否存在,存在直接跳转
                 } else {
                    //设置状态代码404等,跳转404页面
                 }
             }
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
             socket.close();  
          }
   }

处理过来的请求当然要根据输入流解析请求,根据输出流创建响应对象。需要判断是不是后端请求,如果不是后端请求,需要找到对应的文件,设置响应头,设置响应体,返回给浏览器,找不到则返回404。如果是后端请求需要经过servlet,我们肯定需要通过请求路径找到对应的配置文件,我们配置可以放在xml里面,也可以放到map里面,通过反射机制加载某个类,然后实例化某个servlet,处理完设置请求头,设置请求体返回给客户端。

知识点:IPO模型。

一个简单的web服务器的思路已经基本有了,但是为什么springboot应用不用你单独启动服务器?springboot默认使用的是 Tomcat 作为内嵌的服务器。所以,我们搭建一个工程将会变得非常的简单。springboot应用会自动启动一个嵌入的Tomcat服务器实例,至于怎么做到自动的,你问过自己为什么吗?


每周一句|回溯事物本质,对你好的人,永远是敢于说你缺点的人!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 只喝牛奶的杀手 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档