您的位置:首页 > 运维架构 > Shell

简单的具有shell功能的web服务器(带有缓存加速访问的功能)

2014-04-29 09:34 267 查看
一、实验目的
所选题目应该与操作系统原理相关,包含进程的控制,进程间通信,并发控制,文件操作等内容。
二、实验内容
[align=left]实现了一个简单的web服务器,其中使用了内存文件系统加快部分访问量过大的大文件的访问速度,可以减低服务器负载,内嵌了一个简单的shell模块,以协助执行一些shell命令。[/align]
[align=left]主要使用了一下相关知识:[/align]
[align=left]1. 内存共享区[/align]
[align=left]2. 文件系统[/align]
[align=left]3. 信号量[/align]
[align=left]4. 进程控制与同步[/align]
[align=left]5. 进程间通信(管道通信和共享内存区)[/align]
[align=left]6. 线程控制[/align]
[align=left]7. 并发控制[/align]
[align=left]8. 文件操作(读取文件属性,读取文件内容)[/align]
三、实验环境
CPU:P7450 2.13G
内存:2G
操作系统:Ubuntu10.10
实验网络:北京理工大学校园网
四、程序设计与实现
下面我们分几大块来说明我们的程序的实现。
1. shell模块
shell模块中内置了一些命令,内置命令为cd、kill、exit、logout、opensocket(打开服务器)、closesocket(关闭服务器)、log(查看服务器日志)、myls(递归显示服务器内的文件)、load(加载文件进入内存文件系统)、remove(将文件从内存文件系统中删除)、mem(显示内存文件系统中的文件)、look(查看内存文件系统中的文件内容)。这些内部命令都是分别调用了相应的函数和子程序进行执行。
shell模块还支持后台运行&、输入重定向<、输出重定向>、管道|等,主要是先解析输入的命令,如果发现后台运行标志,则在创建子进程后不在wait,输入重定向和输出重定向使用dup2函数复制文件描述符,将标准输出和标准输入的描述符复制到文件的文件描述符,管道的原理也类似,只是利用了进程间通信,将前面程序的输出当做后面的输入。
2. 服务器模块
服务器首先进行初始化,这里主要进行的是建立socket,建立监听,之后建立线程进行accept,如果accept成功,建立一个进程响应请求。
简单HTTP协议如下:
浏览器会发送请求:
[align=left]GET /index.htm HTTP/1.1[/align]
[align=left]Host: 127.0.0.1[/align]
[align=left]Connection: keep-alive[/align]
[align=left]Referer: http://127.0.0.1/[/align] [align=left]User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.57 Safari/534.24[/align]
[align=left]Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5[/align]
[align=left]Accept-Encoding: gzip,deflate,sdch[/align]
[align=left]Accept-Language: en-US,en;q=0.8[/align]
[align=left]Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3[/align]
[align=left]里面包含了浏览器和操作系统,并且指明了连接种类,对于我们有用的只有第一行,浏览器以GET的方式,请求根目录下的index.htm。[/align]
[align=left]响应如下:[/align]
[align=left]HTTP/1.1 200 OK[/align]
[align=left]Content-type:text/html[/align]
[align=left]Connection:close[/align]
[align=left]Content-length:[/align]
[align=left] [/align]
[align=left]//文件内容[/align]
[align=left] [/align]
[align=left] [/align]
[align=left]当然如果找不到文件,则返回状态码为404,告诉浏览器该页面无法找到。[/align]
[align=left]这里注意的是HTTP头与文件内容之间应该以空行分割,以表明文件内容的开始。[/align]
[align=left]其中再接受请求后统计各个文件的访问次数,如果超过设定的阈值则将文件加入到内存文件系统中,在真正的服务器中,有一个服务器缓存机制,就是将访问量过大的大文件例如图片等提前加载到服务器缓存中,这样可以有效地减少打开文件与关闭文件的时间,加快访问速度,减少服务器负载。[/align]
[align=left]另外,服务器模块还在每次请求后打开日志文件,将请求内容记录进入日志,这里利用了信号量互斥访问,防止多个进程同时访问文件出错。[/align]
[align=left]这里还记录了一下每个文件的访问次数,放在如下数据结构:[/align]
[align=left]struct note /*网页访问记录*/[/align]
[align=left]{[/align]
[align=left] char filename[64];[/align]
[align=left] int num;[/align]
[align=left]};[/align]
3. 内存文件系统模块
这里使用的内存文件系统为一个简单的文件系统。当然这里也相应的设置一个互斥信号量,防止多线程同时访问出现问题,防止加载过程中访问出现问题。
struct filemap /*内存文件数据结构*/
{
char name[64];
int begin;
int length;
};
struct memsystem /*内存文件系统结构*/
{
int filenum;
int next;
struct filemap file[32];
};
文件目录表如下:

文件名
起始地址
文件长度
A
002
4
B
007
2
……
……
……
目录后面为简单内存文件系统的数据区。文件系统最多存储32个文件,存放大小最大为8M。
我们建立了文件系统中几种常见的操作,如存入文件、删除文件、查看文件目录内容和产看文件内容。这也方便了不同模块之间的调用,提高了模块内的内聚性,降低了模块间的耦合性。
整个系统的函数说明部分分解过多,依次如下:
/*******************************************************************
P操作
sem_id:信号量集标识
sem_num:信号量标识
*******************************************************************/
void p(int sem_id, int sem_num)
/*******************************************************************
V操作
sem_id:信号量集标识
sem_num:信号量标识
*******************************************************************/
void v(int sem_id, int sem_num)
/*******************************************************************
将文件复制到指定地址,主要用于向内存文件系统中的数据区复制数据
*data:数据区地址指针
*fp:文件操作符
length:文件长度
*******************************************************************/
int copy(char *data,FILE *fp,int length)
/*******************************************************************
将指定路径的文件拷入内存文件系统
*file:文件路径
*******************************************************************/
int load(char *file)
/*******************************************************************
将指定序号的文件删除出内存文件系统
i:文件在内存文件系统中的编号
*******************************************************************/
int rm(int i)
/*******************************************************************
显示内存文件系统中的文件
*******************************************************************/
void mem()
/*******************************************************************
查看内存文件系统中指定编号的文件内容
i:文件在内存文件系统中的编号
*******************************************************************/
void look(int i)
/*******************************************************************
向浏览器返回状态码501
fd:socket描述符
*******************************************************************/
void return_501(int fd)
/*******************************************************************
向浏览器返回状态码404
fd:socket描述符
*******************************************************************/
void return_404(char* file,int fd)
/*******************************************************************
判断是否为文件夹
*file:文件路径
*******************************************************************/
int isdir(char *file)
/*******************************************************************
判断文件是否存在
*file:文件路径
*******************************************************************/
int isexist(char *file)
/*******************************************************************
确定文件类型
*file:文件路径
*******************************************************************/
char * file_type(char *file)
/*******************************************************************
判断是否为cgi文件
*file:文件路径
*******************************************************************/
int iscgi(char *file)
/*******************************************************************
输出状态码为200的http头
*fp:socket文件描述符
*content_type:http返回类型
*******************************************************************/
void header(FILE *fp,char *content_type)
/*******************************************************************
调用子程序显示文件夹中的文件内容
*file:文件路径
fd:socket文件描述符
*******************************************************************/
void do_ls(char *file,int fd)
/*******************************************************************
调用子程序执行cgi
*file:文件路径
fd:socket文件描述符
*******************************************************************/
void exec(char *file,int fd)
/*******************************************************************
调用子程序显示文件内容
*file:文件路径
fd:socket文件描述符
*******************************************************************/
void do_cat(char *file,int fd)
/*******************************************************************
客户端函数,负责与浏览器联络,解析浏览器的请求,响应浏览器的请求
client_fd:socket标识符
*******************************************************************/
void client(int client_fd)
/*******************************************************************
监控浏览器链接请求
*argv:socket标识符
*******************************************************************/
void thread(void * argv)
/*******************************************************************
创建服务器
port:端口号
*******************************************************************/
int server_create(int port)
/*******************************************************************
创建服务器,建立监控线程
port:端口号
*******************************************************************/
int opensock(int port)
/*******************************************************************
shell输出头
*******************************************************************/
void shellheader()
/*******************************************************************
网页浏览记录内存共享区初始化
*******************************************************************/
int notesystem()
/*******************************************************************
内存文件系统内存共享区初始化
*******************************************************************/
int filesystem()
/*******************************************************************
处理ctrl-c
*******************************************************************/
void intHandler()
/*******************************************************************
shell处理输入命令
*******************************************************************/
int shell()
/*******************************************************************
主函数,负责整个程序的调度,初始化
*******************************************************************/
int main(int argc,char *argv[])
以上是我们主要的数据结构和主体设计
本文出自 “天才鸟蛋” 博客,请务必保留此出处http://curley.blog.51cto.com/1627940/816592
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐