美文网首页
微型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