bhttpd
以前产品应用是用串口做控制台,写了一个带简单命令历史和命令补全功能的控制台Shell,用作程序的调试,包括查看系统状态和调试修改设定等等。确实非常好用,对很多现场简单问题的快速定位起到了很好的作用。系统移到 Linux 以后,由于对如何在 Linux 下,在应用程序中如何嵌入控制台 Shell 用作原先的调试功能,不太熟悉,先前想用 Modbus Server,通过改 Modbus 寄存器方式做调试修改,后来发现根本要用的时候记不住,也不直观,不好用,写完了以后,自己就没用过。后来想集成一个 httpd,使用 CGI 接口做程序状态的相识和调试修改设定,于是着手寻找简单的 httpd 的实现。经过一番比较,我认为 bhttpd 非常小,c 文件只有3个,行数只有 104+375+90 行。而且带 CGI 功能,十分适合拿来用。
下来代码以后测试发现,这个代码有问题,不能正常工作。沉下心来,把代码看了一遍,做了一番调试,代码终于正常了。修改后的代码更新在我的 bhttpd 上。其中大概修改如下:
- 字符行分成多个字符串
这个功能基本就是 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 模块,专门放置字符串处理相关的工具函数。
头文件包含:原先的实现,头文件主要包含在 .h 文件中。我始终认为,.h 中应该包含最少的头文件,如果实现需要某个头文件,那么包含应该是在 .c 中。所以大量的包含做了修改。
mime 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的更多相关文章
- [http服务]
[http服务] CentOS 6 httpd 程序环境 记录了httpd的主进程编号: v 主程序文件: /usr/sbin/httpd /usr/sbin/httpd.worker /usr/sb ...
- http服务配置和apache
CentOS 6 httpd 程序环境 记录了httpd的主进程编号: 主程序文件: /usr/sbin/httpd /usr/sbin/httpd.worker /usr/sbin/http ...
随机推荐
- Magic xpa 3.x很容易将数据导出到Excel中
Magic xpa 3.x很方便的将表中数据导出到Excel文件中,还可以自动将表中数据生成各种图表. 通过使用自带的打印数据内部事即可实现. 1.首先将打印数据任务属性设置为“是”. 2.可使用主程 ...
- VC工程产生文件后缀名解释
[原文出自http://hi.baidu.com/zj0932zj/blog/item/b55f33cc7753c01700e92870.html ] .APS:存放二进制资源的中间文件,VC把当前资 ...
- Python-10 字典dict
#1 创建 dict1={'欢欢':'i love','小高高':'you'} dict2={1:'one',2:'two',3:'three'} dict3={} #2 访问元素 print('欢欢 ...
- alpha阶段发布博客
我们的Phylab网站发布了! Alpha版本功能 模块 功能 注册界面 根据邮箱,学号等信息注册新用户 登陆界面 根据账号信息登陆 用户界面 查看,修改用户信息和签名 实验报告界面 查看各个实验预习 ...
- mysql 5.5数据导入5.7 Failed - Error on Table user - 1067 - Invalid default value for 'CREATE_date'
表结构是这样 DROP TABLE IF EXISTS `user`;CREATE TABLE `user` (....省略了一些无关紧要的字段 `CREATE_DATE_` timestamp NO ...
- python_装饰器
越来越觉得写一点技术博客是有多么重要了,明日复明日,现在就开始写吧! 1. 普通装饰器 装饰器的写法是一种语法糖,装饰器也还是一个函数而已,它接收一个函数对象作为参数,并返回一个新函数,主要是拓展原函 ...
- android studio 运行项目时waiting for target device to come online
cmd进入命令行,进入adb所在的目录下: 或者在Terminal中输入命令: adb kill-server adb start-server
- C++_数字时钟
利用C++语言基础,制作了一个模拟电子时钟的程序. #include<iostream> #include<windows.h> //延时与清屏头文件 using namesp ...
- ThreeJs 模型的缩放、移动、旋转 以及使用鼠标对三维物体的缩放
首先我们创建一个模型对象 var geometry = new THREE.BoxGeometry( 100, 100, 100); //边长100的正方体 var material = new TH ...
- Java小白不走弯路学习Java流程以及学习误区
学习Java编程技术肯定是以就业拿到高薪工作为主要目的的,可是高薪不会那么轻易拿到,这是一个最简单的道理.没有付出就没有回报,在整个学习Java编程技术的过程中,你需要付出时间.精力.金钱.废话不多说 ...