美文网首页
微型Web服务器

微型Web服务器

作者: 尧字节 | 来源:发表于2020-06-06 20:56 被阅读0次

CSAPP这本书好厚,曾经一度以为可能买了就是吃灰,很难读完。每次拿起觉得太厚了,简单的翻翻又放下。后来我就不整体看,每周花个1-2个小时的时间,只看一章,看完一章在目录打个勾,而看书的顺序,完全看自己的喜好,没想到,还比较轻松,这么厚的书,可能还有2-3章就读完了,感觉这个办法对于读厚书来说还是不错的。以后就用这种方法读书吧。

这篇文章就是按照第11章的代码来实践和测试一个简单的web服务器,麻雀虽小,五脏俱全。通过简单的实现代码,可以帮助我们了解HTTP协议的基本内容,了解一般的web工作原理。

一 有什么用

除了了解web流程和http协议之外,这个web服务器有什么应用场景那,我想还是有的。比如:

  • 嵌入在你的程序里面,可以做程序的内部状态的监控,前台需要了解程序的运行状态,调用你的http服务就可以了,还不用担心为此单独部署一个web服务器。
  • 在家用路由器等小型的设备上,如果部署个常见的tomcat或jetty,nginx等服务器比较重,占内存和容量都是不可接受的,而且路由器管理的需要的功能有限,可以嵌入这种小型的服务器。
  • 可以做个简单的后门程序

二 Web服务器工作原理

简化版本的http交互流程图如下:


HTTP交互

从上图可以看出,其实web服务器的功能从整体看还是比较简单,就是接受web请求,解析http协议请求内容,然后处理请求,返回。
这里面处理分为两类:

  1. 静态内容处理,比如读取本地的html文件,css文件,图片文件直接返回。
  2. 动态内容处理,比如执行一个可执行文件,将结果返回给客户端。
    静态文件内容处理,没啥好说的,就是读取文件,把内容write发送给客户端;动态内容涉及到的问题比较多,如何把参数传递给服务器,服务器如何调用可执行文件执行,可执行文件的执行结果又以怎么样的形式返回给客户端。一旦有可能产生混乱的地方也就有了标准,CGI就是这个标准。
  • 参数传递: CGI定义了很多环境变量,http服务器可以设置环境变量,调用程序时候,程序通过环境变量:QUERY_STRING 来获取参数。
  • 执行结果返回: 可以将CGI程序的输出重定向到客户端的描述符上,从而达到返回的目的。

三 实践

代码引用了书里面的封装的代码,本想把整个代码都拿出来的,发现可能也挺无聊的,找些重点的有意思的代码分析下,就够了:

// 处理静态文件
void serve_static(int fd, char* filename, int filesize)
{
    int srcfd;
    char *srcp, filetype[MAXLINE], buf[MAXBUF];
    get_filetype(filename, filetype); 
    sprintf(buf, "HTTP/1.0 200 OK\r\n"); 
    sprintf(buf, "%sServer: Tiny Web Server\r\n", buf);
    sprintf(buf, "%sContent-length: %d\r\n", buf, filesize);
    sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype);
    // 将返回头信息发送给客户端
    Rio_writen(fd, buf, strlen(buf)); 


    srcfd = Open(filename, O_RDONLY, 0); 
    srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0); 
    Close(srcfd); 
    Rio_writen(fd, srcp, filesize); 
    Munmap(srcp, filesize);
}

其中:

srcfd = Open(filename, O_RDONLY, 0); 
srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0); 
Close(srcfd); 

Mmap函数创建一个新的只读的私有的虚拟存储器区域,将文件描述符srcfd指向的文件,映射到这个内存区域,返回的是指向新虚拟内存区域的地址,这样可以减少一次内存的拷贝。

看下调用CGI程序提供动态服务的函数:

void serve_dynamic(int fd, char* filename, char* cgiargs)
{
    char buf[MAXLINE], *emptylist[] = { NULL };

    // 返回结果头部设置
    sprintf(buf, "HTTP/1.0 200 OK\r\n");
    Rio_writen(fd, buf, strlen(buf));
    sprintf(buf, "Server: Tiny Web Server\r\n");
    Rio_writen(fd, buf, strlen(buf));
    // 子线程执行 
    if (Fork() == 0) { 
        // 设置CGI 应用使用的参数
        setenv("QUERY_STRING", cgiargs, 1);  
        // 将CGI应用的输出重定向到客户端的socket上去
        Dup2(fd, STDOUT_FILENO); 
       // 执行CGI应用
        Execve(filename, emptylist, environ); 
    }
    // 回收
    Wait(NULL);
}

关键函数就是两步:

        // 设置CGI 应用使用的参数
        setenv("QUERY_STRING", cgiargs, 1);  
        // 将CGI应用的输出重定向到客户端的socket上去
        Dup2(fd, STDOUT_FILENO); 

像上面我们说的一样,CGI程序通过获取QUERY_STRING环境变量来获取它的执行参数。
获取的时候:

// 获取环境变量
char * buf = getenv("QUERY_STRING");

五 测试

5.1 基本html测试:

image.png

5.2 CGI测试

CGI测试

如果改成了系统的一些命令,再增加交互,就是一个后门了。

六诗词欣赏

雨霖铃·寒蝉凄切

[宋]  [柳永] 

寒蝉凄切,对长亭晚,骤雨初歇。
都门帐饮无绪,留恋处,兰舟催发。
执手相看泪眼,竟无语凝噎。
念去去,千里烟波,暮霭沉沉楚天阔。

多情自古伤离别,更那堪冷落清秋节!
今宵酒醒何处?杨柳岸,晓风残月。
此去经年,应是良辰好景虚设。
便纵有千种风情,更与何人说?


相关文章

网友评论

      本文标题:微型Web服务器

      本文链接:https://www.haomeiwen.com/subject/oufftktx.html