Linux网络编程-Web服务器实践


源码链接,失效请评论

1. 题目要求

编译、配置、运行示例Web服务器,分析服务器对静态网页和动态网页的支持原理。

2. 编译运行

在源代码文件夹中的/source文件夹下,先执行make clean命令,清除原先编译生成的文件。

make clean

image-20230507104211176

在使用make命令重新编译生成可执行文件。

make

image-20230507104258001

通过执行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,即配置文件目录错误。

image-20230507110003230

所以我们在相应目录创建文件夹,将defaults/pserv.conf文件复制到相应目录下

image-20230507110346895

重新编译运行程序。可以发现出现了新的错误,再次通过源代码字符查询定位相应报错打印处。

image-20230507110415782

根据错误发生的位置,我们通过网上定位发现,错误的原因在于配置文件../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

image-20230507111918690

default/mime_types.dat文件复制到../usr/local/etc/pserv/目录下;再创建日志文件结构。

image-20230507112219602

再编译运行。发现已经可以正常执行

image-20230507112308503

尝试访问网页http://172.23.157.70:8080/发现无法正常访问,且发现终端中发出了未发现文件的错误。

image-20230507112450460

image-20230507112443544

定位错误信息打印处,再网上定位错误发生处。最终发现是由于defaultFileName变量未初始化复制为默认文件名称导致,我们直接将strcat(completeFilePath, defaultFileName);函数调用的参数defaultFileName修改为DEFAULT_FILE_NAME;除此之外,默认路径位置处于是由于同样的原因,导致无法识别为目录文件,程序执行错误,我们也将其修改为默认定义的变量名;并将default/index.html文件复制到../usr/local/var/www/目录下。

image-20230507112602273

image-20230507112804793

再次编译运行,发现仍然无法发现文件,最终发现原因是由于是由于main.h文件中#define MAX_INDEX_NAME_LEN 16限制了默认路径的长度,我们将其修改为32.

image-20230507114448451

至此我们就已经可以正常的访问静态网页了。

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(&timestamp);
	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;
}

image-20230507115154907

尝试访问http://172.23.157.70:8080/cgi-bin/cgi,发现执行错误,定位错误打印处。

image-20230507115254068

image-20230507115340763

原因是由于==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

image-20230507115732940

再次编译执行,尝试访问。数据发送成功,但是网页解析失败!

image-20230507115822421

发现数据前存在一个数据“end”,似乎是由于这个end导致浏览器误以为数据是字符串,直接按照字符串解析,导致无法解析成html数据。定位到end字符打印处,注释掉打印end的代码。

通过源码追溯,发现打印语句再sendChunk函数处,注释掉红色框的两行代码,再次编译执行。

image-20230507120155275

再次尝试访问http://172.23.157.70:8080/cgi-bin/cgi,访问成功。

image-20230507120314604

4. 总结

经过上述对源码进行的修改,成功编译运行了Web服务器。

通过对源码的阅读学习,可以知道,静态网页的实现原理是服务端直接读取文件数据发送的客户端(浏览器),使浏览器直接解析出相应的网页。

动态网页的实现原理,根据用户的请求执行相应的脚本程序(可执行文件等),输出相应的数据内嵌到写好的html语法中,返回到客户端,使浏览器解析出相应的网页。其中使用到的主要技术是CGI技术,CGI(Common Gateway Interface)是一种用于在 Web 服务器和应用程序之间传递数据的标准协议。通过 CGI,Web 服务器可以调用外部程序处理用户请求,并将处理结果返回给用户。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux网络编程是指在Linux操作系统上编写网络应用程序的过程。它涉及使用各种网络协议和技术来实现网络通信和数据传输。Linux作为一个开源的操作系统,具有高度的灵活性和可定制性,因此它成为许多网络应用程序的首选平台。 Linux网络编程的核心是使用套接字(socket)编程接口。套接字是一种通信机制,通过网络传输数据,可以实现不同主机之间的数据交换。在Linux中,套接字编程可以使用C语言提供的Socket API来实现。通过Socket API,开发者可以创建、连接、发送和接收套接字,并实现基于TCP/IP协议的网络通信。 使用Linux网络编程可以实现各种网络应用程序,如网络服务器、客户端、网络协议的实现等。通过编写网络服务器,我们可以搭建Web服务器、FTP服务器等,以提供网络服务。通过编写客户端程序,可以实现与服务器之间的数据交互,如浏览网页、下载文件等。此外,还可以使用Linux网络编程来实现网络协议,如HTTP、TCP等,以满足特定的需求。 Linux网络编程的重点在于理解网络协议和网络通信的原理,掌握Socket编程接口,并使用合适的工具和技术来进行调试和测试。此外,还需要熟悉Linux操作系统的相关知识,如进程管理、文件系统等,以便更好地进行网络应用程序的开发和调试。 总之,Linux网络编程是一项重要的技能,它可以帮助开发者实现各种复杂的网络应用程序,并为用户提供高效、安全的网络服务。要掌握Linux网络编程,需要深入了解套接字编程接口、网络协议和Linux操作系统,并进行实际的编程练习和实践

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值