《Linux网络编程》综合案例web服务器shttpd

 由于之前没认真学习过http协议及服务端的相关实现,近日有空看到同事有本《Linux网络编程(第2版)》,

遂拾来翻阅,见其中包含一个web服务器的综合案例,于是想认真对照着学习下http的相关开发实现。

孰不知,一涉足才发现这是个坑。

 首先,书本代码不完整,提供的源码链接也并没有该案例源码;

最终从这里http://blog.csdn.net/l979951191/article/details/47443089找到比较全的代码,感谢之;

 其次,代码存在着一些bugs;上述博文链接的作者虽然代码比较全,

最后却没有实现功能,原因就是没有修改其中的bugs;

 再者,提供的代码功能不完整,并没有实现cgi等一些功能。

 写这篇文章只是不想让自己几天的学习没有结果,虽然这本书是个坑,但如果哪位读者不小心也中踩进来了,

可以从这里获得些提醒,然后相互交流一下心得。不知是否该抨击下作者呢,误人子弟?

不过现在的技术书籍繁多,良莠不齐,还真是要看大神们的推荐比较好。


 刚入门其实最好还是可以先看看轻量级tinyhttpd,网上很多解析,github上随便都能找到源码,

https://github.com/search?utf8=%E2%9C%93&q=tinyhttpd&type=Repositories


 鄙人认为实现web服务器的难点,在于如何处理并发和实现cgi。

并发的实现,可以通过维护线程池或者IO多路复用,epoll模型在linux下是比较好的选择。

cgi的实现则涉及到管道通信, 当然cgi已经不常用了,但理解下原理还是有益的。


 下面主要是贴出我发现《linux网络编程》shttpd案例代码有问题的地方,

由于我也是才学习实现http服务器,源码中未实现的功能如post、put、cgi等方法,我也还未想好如何较好的实现。


  1. 解析配置文件函数 void Para_FileParse(char* file)
  a. 解析文本获取值时,没有跳过'/0' 和 '=' ;

 b. 根据关键字判断取值时 strncmp()没有取反。 正确应该如下:

	void Para_FileParse(char* file)
	{
		......
		......
		name = pos;
		while (!isspace(*pos) && *pos != '=') {
			++pos;
		}
		*pos++ = '\0';

		while (isspace(*pos) || *pos == '=') {
			++pos;
		}
		value = pos;
		while (!isspace(*pos) && *pos != '\0' && *pos != '\r' && *pos != '\n') {
			++pos;
		}
		*pos = '\0';
 		int ivalue;
		if (!strncmp("CGIRoot", name, 7)) {
			memcpy(conf_para.CGIRoot, value, strlen(value) + 1);
		} else if (!strncmp("DefaultFile", name, 11)) {
			memcpy(conf_para.DefaultFile, value, strlen(value) + 1);
		} else if (!strncmp("DocumentRoot", name, 12)) {
			memcpy(conf_para.DefaultFile, value, strlen(value) + 1);
		} else if (!strncmp("ListenPort", name, 10)) {
			ivalue = strtol(value, NULL, 10);
			conf_para.ListenPort = ivalue;
		} else if (!strncmp("MaxClient", name, 9)) {
			ivalue = strtol(value, NULL, 10);
			conf_para.MaxClient = ivalue;
		} else if (!strncmp("TimeOut", name, 7)) {
			ivalue = strtol(value, NULL, 10);
			conf_para.TimeOut = ivalue;
		}
		......
		......
	}

2. 查找文件类型、 错误类型的for循环,不是递增指针,而是错误用了++i; 

源码:for(mine = &builtin_mime_types[i]; mine->extension != NULL; i++)
for(err = &_error_http[i];err->status != wctl->conn.con_res.status;i++);

正确: for(mine = &builtin_mime_types[i]; mine->extension != NULL;++mine)
for(err = &_error_http[i];err->status != wctl->conn.con_res.status;++err);

3. 解析请求 int Request_Parse(struct worker_ctl *wctl)
a. 未指定默认index.html文件;
修改为:
snprintf(req->rpath, URI_MAX, "%s%s",conf_para.DocumentRoot, req->uri);
if (req->uri[strlen(req->uri) - 1] == '/') {
     strcat(req->rpath, conf_para.DefaultFile);
}

  然后 Method_DoGet()中 获取请求的文件类型修改为
  mine = Mine_Type(req->rpath, strlen(req->rpath), wctl);  // 原为 req->uri

修改以上问题之后,应该是可以看到静态html文档了。


  其他暂时未完善的问题: 

 1. 源码中uri解析、cgi实现的代码并未用到;uri解析应该是给cgi程序传参时用到的。

其实鄙人认为源码中的cgi实现也是有问题的,执行cgi程序需要用到环境变量或通过管道传参,

但代码中却丝毫没有;

 2. post/put等其他方法需要进一步学习http协议去实现。

 鄙人浅薄之见,欢迎交流讨论。


你可能感兴趣的:(http)