以前产品应用是用串口做控制台,写了一个带简单命令历史和命令补全功能的控制台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. docker学习记录

    Container 容器是一种基础工具, 泛指任何容纳其他物品的工具, 可以部分或者完全封闭,被用于容纳,储存, 运输物品, 物体可以放置在容器中, 而容器可以保护内容物 1 Docker Objec ...

  2. DevExpress 折线图和柱状图的绘制与数据绑定

    DevExpress 组件是一个非常丰富和强大的组件,适合各种可视化图形的绘制与展示,在数据分析展示中是个很有帮助的,网上也有很多关于这方面的文章,关于折线图或柱状图的画法,以下是自己在工作中接触到的 ...

  3. uni-app 调用支付宝支付

    本文讲解  uni-app如何调用支付宝进行支付,服务端为 .net编写. 客户端:uni-app 编写  1.根据服务端生成的订单信息发起支付. 服务端:.net 编写 1.生成订单信息.2.接收支 ...

  4. JS禁用浏览器前进后退

    <script language="javascript"> //防止页面后退 history.pushState(null, null, document.URL); ...

  5. Javascript FormData实例

    一.创建一个formData对象实例的方式 1.创建一个空对象 var formData = new FormData();//通过append方法添加数据 1 2.使用已有表单来初始化对象 //表单 ...

  6. Python爬虫与数据分析之模块:内置模块、开源模块、自定义模块

    专栏目录: Python爬虫与数据分析之python教学视频.python源码分享,python Python爬虫与数据分析之基础教程:Python的语法.字典.元组.列表 Python爬虫与数据分析 ...

  7. Eclipse Tomcat部署web项目时出现There are no resources that can be added or removed from the server解决办法

    问题原因是:tomcat版本和java版本不匹配.

  8. Canvas 实现绘制图表

    这里用canvas实现了两个简单的图表,用到了canvas的基本用法,效果如下 新建 chart.js 文件,封装绘制方法 构造方法 function myChart(config){ this.wi ...

  9. Android App专项测试(压力测试)

    转载https://blog.csdn.net/qq_29794757/article/details/64160303 转载https://blog.csdn.net/xuejiaodream/ar ...

  10. python杂记二

    1. 写文件可以直接使用print函数 file_name = open("file_name.txt","w") print("file conta ...