文档章节

boa阅读笔记5

开源中国精神科主任
 开源中国精神科主任
发布于 2014/11/10 09:52
字数 857
阅读 14
收藏 0
    create_common_env();
    build_needs_escape();

    if (max_connections < 1) {
        struct rlimit rl;

        /* has not been set explicitly */
        c = getrlimit(RLIMIT_NOFILE, &rl);    //获得系统的限制
        if (c < 0) {
            perror("getrlimit");
            exit(1);
        }
        max_connections = rl.rlim_cur;        //根据系统限制设置最大连接数
    }

    /* background ourself */
    if (do_fork) {                            //父进程退出,子进程转换为守护进程
        switch(fork()) {
        case -1:
            /* error */
            perror("fork");
            exit(1);
            break;
        case 0:
            /* child, success */
            break;
        default:
            /* parent, success */
            exit(0);
			//break?????
            break;
        }
    }

我们接着从create_common_env开始介绍。

void create_common_env()
{
    int index = 0, i;


    /* NOTE NOTE NOTE:
       If you (the reader) someday modify this chunk of code to
       handle more "common" CGI environment variables, then bump the
       value COMMON_CGI_COUNT in defines.h UP

       Also, in the case of document_root and server_admin, two variables
       that may or may not be defined depending on the way the server
       is configured, we check for null values and use an empty
       string to denote a NULL value to the environment, as per the
       specification. The quote for which follows:

       "In all cases, a missing environment variable is
       equivalent to a zero-length (NULL) value, and vice versa."
     */
    common_cgi_env[index++] = env_gen_extra("PATH",
                                            ((cgi_path != NULL) ? cgi_path : DEFAULT_PATH), 0);
    common_cgi_env[index++] = env_gen_extra("SERVER_SOFTWARE", SERVER_VERSION, 0);
    common_cgi_env[index++] = env_gen_extra("SERVER_NAME", server_name, 0);
    common_cgi_env[index++] = env_gen_extra("GATEWAY_INTERFACE", CGI_VERSION, 0);

    common_cgi_env[index++] =
        env_gen_extra("SERVER_PORT", simple_itoa(server_port), 0);

    /* NCSA and APACHE added -- not in CGI spec */
    /* common_cgi_env[index++] = env_gen_extra("DOCUMENT_ROOT", document_root); */

    /* NCSA added */
    /* common_cgi_env[index++] = env_gen_extra("SERVER_ROOT", server_root); */

    /* APACHE added */
    common_cgi_env[index++] = env_gen_extra("SERVER_ADMIN", server_admin, 0);
    common_cgi_env[index] = NULL;

    /* Sanity checking -- make *sure* the memory got allocated */
    if (index > COMMON_CGI_COUNT) {
        log_error_time();
        fprintf(stderr, "COMMON_CGI_COUNT not high enough.\n");
        exit(1);
    }

    for(i = 0;i < index;++i) {
        if (common_cgi_env[i] == NULL) {
            log_error_time();
            fprintf(stderr, "Unable to allocate a component of common_cgi_env - out of memory.\n");
            exit(1);
        }
    }
}

上面的代码应该是在设置cgi的环境变量,并最后进行一次环境变量检测。

void build_needs_escape(void)
{
    unsigned int a, b;
    const unsigned char special[] =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz"
        "0123456789"
        "-_.!~*'():@&=+$,/?";
    /* 21 Mar 2002 - jnelson - confirm with Apache 1.3.23 that '?'
     * is safe to leave unescaped.
     */
    unsigned short i, j;

    b = 1;
    for (a=0; b!=0; a++) b=b<<1;
    /* I found $a bit positions available in an unsigned long. */
    if (a < NEEDS_ESCAPE_WORD_LENGTH) {
        fprintf(stderr,
                "NEEDS_ESCAPE_SHIFT configuration error -- "\
                "%d should be <= log2(%d)\n",
                NEEDS_ESCAPE_SHIFT, a);
        exit(1);
    } else if (a >= 2*NEEDS_ESCAPE_WORD_LENGTH) {
        /* needs_escape_shift configuration suboptimal */
    } else {
        /* Ahh, just right! */;
    }
    memset(_needs_escape, ~0, sizeof(_needs_escape));
    for(i = 0; i < sizeof(special) - 1; ++i) {
        j=special[i];
        if (j>=NEEDS_ESCAPE_BITS) {
            /* warning: character $j will be needlessly escaped. */
        } else {
            _needs_escape[NEEDS_ESCAPE_INDEX(j)]&=~NEEDS_ESCAPE_MASK(j);
        }
    }
}

看函数名应该跟编解码有关,浏览代码后初步确定是创建了程序需要的编码对照表,方便server快速编解码。

    /* main loop */
    timestamp();

    status.requests = 0;
    status.errors = 0;

    start_time = current_time;

    #if defined _kqueue
        kqueue_loop(server_s);

    #elif defined _epoll
        epoll_loop(server_s);

    #else
        select_loop(server_s);

    #endif

    return 0;
}

最后就是进入主循环了,先是记录当前时间,然后根据系统情况以先后次序选择kqueue、epoll、和select之一进行socket端口的监听循环。

void select_loop(int server_s)
{
    FD_ZERO(&block_read_fdset);
    FD_ZERO(&block_write_fdset);
    /* set server_s and req_timeout */
    req_timeout.tv_sec = (ka_timeout ? ka_timeout : REQUEST_TIMEOUT);
    req_timeout.tv_usec = 0l;   /* reset timeout */

    /* preset max_fd */
    max_fd = -1;

    while (1) {
        if (sighup_flag)
            sighup_run();
        if (sigchld_flag)
            sigchld_run();
        if (sigalrm_flag)
            sigalrm_run();

        if (sigterm_flag) {
            if (sigterm_flag == 1)
                sigterm_stage1_run(server_s);
            if (sigterm_flag == 2 && !request_ready && !request_block) {
                sigterm_stage2_run();
            }
        }

        /* reset max_fd */
        max_fd = -1;

        if (request_block)
            /* move selected req's from request_block to request_ready */
            fdset_update();

        /* any blocked req's move from request_ready to request_block */
        process_requests(server_s);

        if (!sigterm_flag && total_connections < (max_connections - 10)) {
            BOA_FD_SET(server_s, &block_read_fdset); /* server always set */
        }

        req_timeout.tv_sec = (request_ready ? 0 :
                              (ka_timeout ? ka_timeout : REQUEST_TIMEOUT));
        req_timeout.tv_usec = 0l;   /* reset timeout */

        if (select(max_fd + 1, &block_read_fdset,
                   &block_write_fdset, NULL,
                   (request_ready || request_block ? &req_timeout : NULL)) == -1) {
            /* what is the appropriate thing to do here on EBADF */
            if (errno == EINTR)
                continue;   /* while(1) */
            else if (errno != EBADF) {
                DIE("select");
            }
        }

        time(&current_time);
        if (FD_ISSET(server_s, &block_read_fdset))
            pending_requests = 1;
    }
}

因为对select比较熟悉,因此拿select_loop来分析。在主循环中先对状态标志进行了分析和处理,如果有请求阻塞,则把请求移到就绪队列进行处理,然后对请求进行超时处理,最后再次进行select监听读写请求。

对boa的解读就先到这里了,由于对http服务的了解还不多,因此也无法进行更细致的业务分析,只能讲解个大概,以后研究http协议时再来做详细的分析。

© 著作权归作者所有

共有 人打赏支持
开源中国精神科主任
粉丝 1
博文 18
码字总数 26787
作品 0
杭州
SylixOS移植Boa服务器

1. Boa简介 Boa是一种非常小巧的Web服务器,其可执行代码只有大约60KB左右。作为一种单任务Web服务器,Boa只能依次完成用户的请求,而不会fork出新的进程来处理并发连接请求。但Boa支持CGI,...

遗忘丶彻底
2017/07/10
0
0
boa与cgic库写cgi简介

嵌入式 WEB 服务器 BOA 和 CGI 一、嵌入式 WEB 服务器 BOA 简介 嵌入式 WEB 服务器常见的有: boa lighttpd shttpd thttpd mathopd minihttpd appweb goahead 随着 Internet 技术的兴起,在嵌...

唧唧帝
2014/01/15
0
0
嵌入式Web服务器移植

第一步 Boa程序的移植 1、下载Boa源码 下载地址:http://www.boa.org/, 或者http://sourceforge.net 最新发行版本: 0.94.13 下载 boa-0.94.13.tar.gz,注意:从boa上下载的是boa-0.94.13.t...

晨曦之光
2012/03/09
42
0
Python学习札记(2)——搭建Boa-constructor

一、Boa-constructor是什么 看看来自己百度的解释:Boa Constructor是一个跨平台的Python集成开发环境和wxPython图形用户界面构建器。它提供了可视化方式的框架(窗口) 的创建 和处理、对象...

东方卯
2014/03/04
0
2
Python集成开发环境--Boa Constructor

boa-constructor是一个跨平台的Python集成开发环境和wxPython图形用户界面构建器。它提供了可视化方式的框架(窗口) 的创建 和处理、对象检视器(object inspector)、编辑器、继承的等级、h...

匿名
2008/09/14
22.9K
2

没有更多内容

加载失败,请刷新页面

加载更多

初级开发-编程题

` public static void main(String[] args) { System.out.println(changeStrToUpperCase("user_name_abc")); System.out.println(changeStrToLowerCase(changeStrToUpperCase("user_name_abc......

小池仔
今天
8
0
现场看路演了!

HiBlock
昨天
19
0
Rabbit MQ基本概念介绍

RabbitMQ介绍 • RabbitMQ是一个消息中间件,是一个很好用的消息队列框架。 • ConnectionFactory、Connection、Channel都是RabbitMQ对外提供的API中最基本的对象。Connection是RabbitMQ的s...

寰宇01
昨天
12
0
官方精简版Windows10:微软自己都看不过去了

微软宣布,该公司正在寻求解决方案,以减轻企业客户的Windows 10规模。该公司声称,企业客户下载整个Windows 10文件以更新设备既费钱又费时。 微软宣布,该公司正在寻求解决方案,以减轻企业...

linux-tao
昨天
20
0
TypeScript基础入门之JSX(二)

转发 TypeScript基础入门之JSX(二) 属性类型检查 键入检查属性的第一步是确定元素属性类型。 内在元素和基于价值的元素之间略有不同。 对于内部元素,它是JSX.IntrinsicElements上的属性类型...

durban
昨天
13
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部