以前产品应用是用串口做控制台,写了一个带简单命令历史和命令补全功能的控制台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 != '\0')) str++;
if (*str == '\0') break;
*str = '\0'; str++;
while (*str == split_char) str++;
if (*str == '\0') 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.\n", len);
close(fds[i].fd);
fds[i].fd = -1;
--polled;
}

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

bhttpd的更多相关文章

  1. [http服务]

    [http服务] CentOS 6 httpd 程序环境 记录了httpd的主进程编号: v 主程序文件: /usr/sbin/httpd /usr/sbin/httpd.worker /usr/sb ...

  2. http服务配置和apache

    CentOS 6 httpd 程序环境 记录了httpd的主进程编号:    主程序文件: /usr/sbin/httpd /usr/sbin/httpd.worker /usr/sbin/http ...

随机推荐

  1. C# 时钟控件

    //控件名:myNewClock //作者:刘典武 //时间:2011-06-10 using System; using System.Collections.Generic; using Syst ...

  2. 部署GlusterFS及Heketi

    一.前言及环境 在实践kubernetes的StateFulSet及各种需要持久存储的组件和功能时,通常会用到pv的动态供给,这就需要用到支持此类功能的存储系统了.在各类支持pv动态供给的存储系统中, ...

  3. Java——String类中的compareTo方法总结

    String类的定义:    java.lang  类 String   java.lang.Object      java.lang.String 所有已实现的接口:Serializable, C ...

  4. 人只能靠自己 编写ETL框架使用工具

    今天开始接触到大数据模块,etl 框架工具目的是对医院中的PACS 和RIS 系统进行数据提取: 目前只查到需要用etl工具,大数据板块 ,具体实现仍是大问题 有缘人看到可以留言提示啊:

  5. Google推出了Python最牛逼的编辑器

    环境配置对于大多数人来说都是拦路虎,我们小白往往不知道: 怎么正确的安装 不知道选择什么 怎么安装常用的第三方库 ... Google推出了一个在线的网站 https://colab.research ...

  6. 检测mysq组复制的脚本

    #!/bin/bash PROG_OUT="/root/checkmysql-group.log" # 输出日志到至此文件,建议配置绝对路径 #PROG_OUT="/de ...

  7. bits change world

    No code is the best way to write secure and reliable applications. Write nothing; deploy nowhere.

  8. 001_angular4.0框架学习

    1. Cannot find module 'angular2-in-memory-web-api' 报这个错误的时候  是没有安装这个包  要手动安装下包  命令: npm i angular-in ...

  9. python3下最简单的九九乘法表

    def minus(): print("=========================九九乘法表===========================") x=1 y=1 wh ...

  10. 基于MPI的大规模矩阵乘法问题

    转载请注明出处. /* Function:C++实现并行矩阵乘法; Time: 19/03/25; Writer:ZhiHong Cc; */ 运行方法:切到工程文件x64\Debug文件下,打开命令 ...