源码链接,失效请评论
1. 题目要求
编译、配置、运行示例Web服务器,分析服务器对静态网页和动态网页的支持原理。
2. 编译运行
在源代码文件夹中的/source文件夹下,先执行make clean命令,清除原先编译生成的文件。
make clean
在使用make命令重新编译生成可执行文件。
make
通过执行dhttpd可执行文件,运行Web服务器,但由于配置问题,需要对配置文件和源代码文件进行相应修改才能够正常运行。
./dhttpd
3. 修改配置
通过阅读main.h文件的默认配置路径,大致可以知道,默认的配置文件应该是放置在根目录的文件夹中,由于考虑到对根目录的文件夹添加文件和修改文件可能会造成不安全的因素以及操作起来相对比较麻烦,所以我们在源代码的上一级目录新建usr和etc文件夹,将其模拟为根目录下的usr和etc文件夹,通过修改源代码的默认的绝对路径为相对路径即可,即在每个默认地址之前加上../
表示从上一级目录寻找相应的文件夹。
- 修改前
/* --- Configure options --- */
#define CONFIG_FILE_NAME "pserv.conf" /* name of the configuration file, concatenated to DEFAULT_CONFIG_LOCATION */
#define SERVER_SOFTWARE_STR "pServ"
#define SERVER_VERSION_STR PACKAGE_VERSION
#define CGI_MATCH_STRING "/cgi-bin/"
#define CGI_VERSION "CGI/1.1"
#define MIME_TYPE_DEFAULT "application/octet-stream"
/* configuration file location */
#define DEFAULT_CONFIG_LOCATION "/usr/local/etc/pserv/"
/* hard-wired defaults, if loading of config file fails */
#define DEFAULT_PORT 2000
#define DEFAULT_MAX_CHILDREN 5
#define DEFAULT_DOCS_LOCATION "/usr/local/var/www"
#define DEFAULT_FILE_NAME "index.html"
#define DEFAULT_SEC_TO 1
#define DEFAULT_USEC_TO 100
#define DEFAULT_LOG_FILE "/usr/local/var/log/pserv.log"
#define DEFAULT_MIME_FILE "/usr/local/etc/pserv/mime_types.dat"
#define DEFAULT_CGI_ROOT "/usr/local/var/www/cgi-bin"
#define DEFAULT_SERVER_NAME "localhost"
- 修改后
/* --- Configure options --- */
#define CONFIG_FILE_NAME "pserv.conf" /* name of the configuration file, concatenated to DEFAULT_CONFIG_LOCATION */
#define SERVER_SOFTWARE_STR "pServ"
#define SERVER_VERSION_STR PACKAGE_VERSION
#define CGI_MATCH_STRING "/cgi-bin/"
#define CGI_VERSION "CGI/1.1"
#define MIME_TYPE_DEFAULT "application/octet-stream"
/* configuration file location */
#define DEFAULT_CONFIG_LOCATION "../usr/local/etc/pserv/"
/* hard-wired defaults, if loading of config file fails */
#define DEFAULT_PORT 2000
#define DEFAULT_MAX_CHILDREN 5
#define DEFAULT_DOCS_LOCATION "../usr/local/var/www"
#define DEFAULT_FILE_NAME "index.html"
#define DEFAULT_SEC_TO 1
#define DEFAULT_USEC_TO 100
#define DEFAULT_LOG_FILE "../usr/local/var/log/pserv.log"
#define DEFAULT_MIME_FILE "../usr/local/etc/pserv/mime_types.dat"
#define DEFAULT_CGI_ROOT "../usr/local/var/www/cgi-bin"
#define DEFAULT_SERVER_NAME "localhost"
3.1 静态网页配置
根据编译运行的错误信息,从源码中寻找打印错误的地方。
发现错误发生在main.c源码文件中,原因是无法打开相应名称的文件。
网上寻找configFile变量的赋值处,发现打开的文件目录为../usr/local/etc/pserv/pserv.conf
,即配置文件目录错误。
所以我们在相应目录创建文件夹,将defaults/pserv.conf
文件复制到相应目录下
重新编译运行程序。可以发现出现了新的错误,再次通过源代码字符查询定位相应报错打印处。
根据错误发生的位置,我们通过网上定位发现,错误的原因在于配置文件../usr/local/etc/pserv/pserv.conf
中的配置发生错误。
将配置文件的名称进行进行修改,修改后的../usr/local/etc/pserv/pserv.conf
文件内容
port 8080
max_child 4
documentsPath /usr/local/var/www
defaultFile index.html
secTimeout 1
uSecTimeout 100000
logFile ../usr/local/var/log/pserv.log
mimeTypesFile ../usr/local/etc/pserv/mime_types.dat
cgiroot ../usr/local/var/www/cgi-bin
再次编译运行程序。发生了新的错误,再次定义错误打印处,发现此处的错误是由于没有创建相应的日志文件pserv.log和配置文件mime_types.dat
将default/mime_types.dat
文件复制到../usr/local/etc/pserv/
目录下;再创建日志文件结构。
再编译运行。发现已经可以正常执行
尝试访问网页http://172.23.157.70:8080/
发现无法正常访问,且发现终端中发出了未发现文件的错误。
定位错误信息打印处,再网上定位错误发生处。最终发现是由于defaultFileName变量未初始化复制为默认文件名称导致,我们直接将strcat(completeFilePath, defaultFileName);函数调用的参数defaultFileName修改为DEFAULT_FILE_NAME;除此之外,默认路径位置处于是由于同样的原因,导致无法识别为目录文件,程序执行错误,我们也将其修改为默认定义的变量名;并将default/index.html
文件复制到../usr/local/var/www/
目录下。
再次编译运行,发现仍然无法发现文件,最终发现原因是由于是由于main.h文件中#define MAX_INDEX_NAME_LEN 16
限制了默认路径的长度,我们将其修改为32.
至此我们就已经可以正常的访问静态网页了。
3.2 动态网页配置
首先我们先编写cgi可执行文件,程序如下:
#include<iostream>
#include<time.h>
using namespace std;
int main()
{
char myStr[25] = {0};
time_t timestamp = time(NULL);
struct tm *now = gmtime(×tamp);
now->tm_hour += 8;
printf("\n<HTML>\n\t<Head>\n\t\t<title>\n\t\t\tCGI success\n\t\t</title>\n\t</Head>\n<Body>\n\t\t<H1>\n\t\t\tCGIExec success\n\t\t</H1>\n\t</Body>\n</HTML>\n");
std::string myFormat = "%Y-%m-%d:%H:%M:%S";
strftime(myStr, sizeof(myStr), myFormat.c_str(), now);
for(int i = 0; myStr[i]; i++) {
cout << myStr[i];
}
return 0;
}
尝试访问http://172.23.157.70:8080/cgi-bin/cgi
,发现执行错误,定位错误打印处。
原因是由于==execve(completedPath, newArgv, newEnvp);==执行失败。通过打印completedPath路径,发现路径似乎没有问题。但是通过阅读源码发现,再该函数执行之前,存在代码对工作目录进行修改,导致再新的工作目录下的执行函数出错
类似于如下执行可执行文件,导致从出错,所以我们注释上述修改工作目录的代码
candy@DESKTOP-3F9T5KO:/mnt/d/StudyFile/网络编程/web_server/web_develop/usr/local/var/www/cgi-bin$ ../usr/local/var/www/cgi-bin/cgi
再次编译执行,尝试访问。数据发送成功,但是网页解析失败!
发现数据前存在一个数据“end”,似乎是由于这个end导致浏览器误以为数据是字符串,直接按照字符串解析,导致无法解析成html数据。定位到end
字符打印处,注释掉打印end
的代码。
通过源码追溯,发现打印语句再sendChunk函数处,注释掉红色框的两行代码,再次编译执行。
再次尝试访问http://172.23.157.70:8080/cgi-bin/cgi
,访问成功。
4. 总结
经过上述对源码进行的修改,成功编译运行了Web服务器。
通过对源码的阅读学习,可以知道,静态网页的实现原理是服务端直接读取文件数据发送的客户端(浏览器),使浏览器直接解析出相应的网页。
动态网页的实现原理,根据用户的请求执行相应的脚本程序(可执行文件等),输出相应的数据内嵌到写好的html语法中,返回到客户端,使浏览器解析出相应的网页。其中使用到的主要技术是CGI技术,CGI(Common Gateway Interface)是一种用于在 Web 服务器和应用程序之间传递数据的标准协议。通过 CGI,Web 服务器可以调用外部程序处理用户请求,并将处理结果返回给用户。