admin管理员组

文章数量:1559082

webserver介绍

这个webserver类是对整个web服务器的抽象。在这个类中,调用之前编写的四大模块:httpconnection类、epoller类、timer类以及threadpool类完成整个服务器项目的功能。

webserver的逻辑

第一步是服务器的初始化。在webserver的构造函数中完成对httpconnection类、epoller类、timer类以及threadpool类对象的初始化,同时还需要设置好服务器的socket,暴露端口等相关信息

    m_port = port;
    initeventmode(trigmode);
    m_timeoutms = timeoutms;
    m_openlinger = optlinger;
    m_pool = std::make_unique<threadpool>(threadnum);
    m_timer = std::make_unique<timemanager>();
    m_epoller = std::make_unique<epoller>();
    m_isclose = (initsocket() ? false : true);

本项目是使用i/o多路复用技术中的epoll,在初始化socket的过程中,将m_listenfd加入中epoll池中。同时,也将监听socket的行为(是否有新的连接)和监听每一个http连接的行为(已经建立的连接有无io请求)统一起来了。在每一次直接处理所有的epoll就绪事件时,通过就绪事件的fd可以区分开新连接和i/o请求,并对两种不同的情况分别处理。

第二步是开始处理http连接。

一开始要先清理过期的连接,并且得到下一次处理的时间。这里使用timer指针调用timer类对象的getnexthandle()函数:

    timems = m_timer->getnexthandle();

将得到的时间传递给epoll_wait函数作为时间参数,经过相应的时间等待后,得到发生改变的事件,用一个循环处理所有的epoll就绪事件。在过程中需要分两种类型:收到新的http请求和其他的读写请求。

  1. 收到新的http请求的情况

在fd==m_listenfd的时候,也就是收到新的http请求的时候,需要调用函数

    void handlelisten();
  1. 已经建立连接的http发来io请求的情况

这种情况下,必然需要提供读写的处理,用下述两个函数完成:

    void handlewrite(httpconnection *client);
    void handleread(httpconnection *client);

为了提高性能,使用了线程池,所以这两个函数就是将读写的底层实现函数加入到线程池,两个读写的底层实现函数为:

    void onread(httpconnection* client);
    void onwrite(httpconnection* client);

听到这里大家也许有点懵?这个读和写的过程在webserver类中,是这样的:

  • 读:
    调用handlewrite–>将onread函数扔给线程池去执行
    而onread函数是调用httpconnection对象的读取函数,而httpconnection的读取函数实际上是buffer类对象的读取函数的封装
    简而言之,在handleread函数中,就是让线程池去执行buffer对象中读取函数,获取通信的内容。在onread函数中读取完成后,再调用httpconnection的处理函数,将读取完的数据进行一个相应的处理,具体的处理过程可以查看我之前写的http的文档

  • 写:
    调用handlewrite–>将onwrite函数扔给线程池去执行
    同onread函数一样,在onwrite函数中,其核心函数是buffer对象中的发送函数。在onwrite函数中,如果发送数据有错误产生的话,会根据错误号和发送数据的返回值,判断数据发送出现哪种问题:

    • 某些原因导致发送字节数 == 0:重新处理接收到数据,等待下一次的发送?
    • 返回值-1,进一步根据系统错误号判断:
      • 错误号为eagain:重置为写状态,下一次epoll检测后,再次发送
      • 其他错误:直接关闭通信

epoll使用的是边缘触发et,此外在读结束的时候根据需要改变epoll的事件。

本文标签: 服务器