• bhttpd


    以前产品应用是用串口做控制台,写了一个带简单命令历史和命令补全功能的控制台Shell,用作程序的调试,包括查看系统状态和调试修改设定等等。确实非常好用,对很多现场简单问题的快速定位起到了很好的作用。系统移到 Linux 以后,由于对如何在 Linux 下,在应用程序中如何嵌入控制台 Shell 用作原先的调试功能,不太熟悉,先前想用 Modbus Server,通过改 Modbus 寄存器方式做调试修改,后来发现根本要用的时候记不住,也不直观,不好用,写完了以后,自己就没用过。后来想集成一个 httpd,使用 CGI 接口做程序状态的相识和调试修改设定,于是着手寻找简单的 httpd 的实现。经过一番比较,我认为 bhttpd 非常小,c 文件只有3个,行数只有 104+375+90 行。而且带 CGI 功能,十分适合拿来用。

    下来代码以后测试发现,这个代码有问题,不能正常工作。沉下心来,把代码看了一遍,做了一番调试,代码终于正常了。修改后的代码更新在我的 bhttpd 上。其中大概修改如下:

    1. 字符行分成多个字符串

    这个功能基本就是 C# 的 split 方法,原实现类似于:

    char buf[BUFFER_SIZE];
    char basic_request[3][BUFFER_SIZE];
    // other codes
    read_line(buf, sockfd);
    sscanf(buf, "%s %s %s", basic_request[METHOD], basic_request[PATH], basic_request[PROC]);
    

    这个方法很简单,就是比较浪费内存。当然似乎在系统上,这点内存可能不算啥。但是对于嵌入的人来说,不能忍受,做了一个原地切割为多个字符串的函数来处理:

    int str_split(char *str, char split_char, char **ret, int max_ret)
    {
    	int ret_num = 0, i;
    	memset(ret, 0, max_ret*sizeof(*ret));
    	while (ret_num < max_ret) {
    		*ret++ = str;
    		ret_num++;
    		while ((*str != split_char) && (*str != '')) str++;
    		if (*str == '') break;
    		*str = ''; str++;
    		while (*str == split_char) str++;
    		if (*str == '') break;
    	}
    
    	for (i = ret_num; i < max_ret; i++)	// all other pointers set to NULL string
    		*ret++ = str;
    	return ret_num;
    }
    

    由此,独立出来一个单独的 strlibs 模块,专门放置字符串处理相关的工具函数。

    1. 头文件包含:原先的实现,头文件主要包含在 .h 文件中。我始终认为,.h 中应该包含最少的头文件,如果实现需要某个头文件,那么包含应该是在 .c 中。所以大量的包含做了修改。

    2. mime 3级加速表,改动态分配为全静态分配。因为不管如何,他的元素始终是这么多的,那就不如静态分配,对调试更有利,也更易理解。

    3. tcp 连接 close() 调用问题

    其实,这个问题才是这个库不能工作的最终原因。其解释可以见 The ultimate SO_LINGER page, or: why is my tcp not reliable 代码修改为:

    if(fds[i].fd!=-1&&(fds[i].revents & POLLRDNORM)) {
        handle_request(mime_tbl, cgi_tbl, conf.pub_dir, conf.default_page, fds[i].fd);
        close(fds[i].fd);
        fds[i].fd = -1;
        --polled;
    }
    

    修改为:

    if (fds[i].fd != -1 && (fds[i].revents & POLLRDNORM)) {
    	handle_request(mime_tbl, cgi_tbl, conf.pub_dir, conf.default_page, fds[i].fd);
    	shutdown(fds[i].fd, SHUT_WR);
    	while ((len = recv(fds[i].fd, buff, sizeof(buff), 0)) > 0) fprintf(stderr, "recv before close get %d.
    ", len);
    	close(fds[i].fd);
    	fds[i].fd = -1;
    	--polled;
    }
    

    注意 shutdown() 函数以后后面的 recv() 函数循环。

  • 相关阅读:
    ubuntu安装php的 mongodb扩展
    ubuntu安装php的 redis扩展
    Ubuntu14.04下安装Composer
    编译安装php
    RabbitMQ PHP扩展安装
    编译安装opssl
    安装卸载nginx
    本地VM安装虚拟机,使用xshell连接
    下载并破解IntelliJ IDEA(2017)
    symfony框架中使用service
  • 原文地址:https://www.cnblogs.com/dabbler/p/9464064.html
Copyright © 2020-2023  润新知