用C一步步开发web服务器(4)

在教程1,教程2,教程3的带领下,大家肯定迫不及待进行教程4的开发了吧,这一章节,我们要完成现在这个webserver的所有功能,支持php动态页面以及报错404页面的开发,先展示下最终实现的界面

用C一步步开发web服务器(4)_第1张图片
用C一步步开发web服务器(4)_第2张图片

话不多说,先支持PHP再说
1.浏览器输入

http://localhost:8000/index.php

可见,他是指向当前目录下的index.php文件,所以先在这个目录下创建文件




鹏哥的第一个web服务器


 "1",
    "name"=> "pengge",
    "aaa" => "sdsdd",
    "yes" => "sdsdfsfsff"
);
echo "
";
var_dump($array);
?>



2.顺着教程3的思路,解析filename的文件名,发现他是.php文件,所以我们不能直接文件读取他的内容,我们需要通过php脚本执行该文件内容,然后输出到浏览器上
重写wrap_response方法,使其支持php

/**
 * @desc 封装response  支持静态页面以及php页面
 *
 */
void wrap_response(int connfd,char *filename) {
    struct stat sbuf;
    int filefd,phpfd;
    char *php_result;
    char *srcp;
    char response[MAXLINE],filetype[MAXLINE];
    if(stat(filename,&sbuf) < 0) {
        error_response(connfd);
        exit(1);
    }else {
        
        //获取文件类型
        get_filetype(filename,filetype);
        
        //打开文件并将其写入内存,并由浏览器展示
        filefd = open(filename,O_RDONLY);
        //走php脚本执行输出
        if(strstr(filename, ".php")) {
            sprintf(response, "HTTP/1.1 200 OK\r\n");
            sprintf(response, "%sServer: Pengge Web Server\r\n",response);
            sprintf(response, "%sConnection: close\r\n",response);
            sprintf(response, "%sContent-type: %s\r\n\r\n",response,filetype);
            Write(connfd, response, strlen(response));
            printf("Response headers:\n");
            printf("%s\n",response);
            php_cgi(filename, connfd);
            Close(connfd);
            exit(1);
        //走静态页面输出
        }else {
            
            //拼接静态文件的response头
            sprintf(response, "HTTP/1.0 200 OK\r\n");
            sprintf(response, "%sServer: Pengge Web Server\r\n",response);
            sprintf(response, "%sConnection: close\r\n",response);
            sprintf(response, "%sContent-length: %lld\r\n",response,sbuf.st_size);
            sprintf(response, "%sContent-type: %s\r\n\r\n",response,filetype);
            Write(connfd, response, strlen(response));
            printf("Response headers:\n");
            printf("%s\n",response);
            srcp = mmap(0, sbuf.st_size, PROT_READ, MAP_PRIVATE, filefd, 0);
            Close(filefd);
            //清空srcp空间
            Write(connfd, srcp, sbuf.st_size);
            munmap(srcp, sbuf.st_size);
        }
    }
}

这里有个

php_cgi(filename, connfd);

这个方法,这个就是执行php脚本输出到页面的方法,我们可以这样写

void php_cgi(char* script_path, int fd) {
    dup2(fd, STDOUT_FILENO);
    execl("/usr/bin/php","/usr/bin/php",script_path,(char *) NULL);
}

大家可以查查dup2跟execl的用法,这里不介绍了

综上,我们完成了支持PHP的webserver


接下来,我们要进行404错误界面的开发了,
浏览器输入

http://localhost:8000/index1.php

1.因为不存在这个页面,所以我们需要像nginx一样,创建一个404页面


404 Not Found

404 Not Found


Pengge Server/1.0

2.在stat(filename,&sbuf)方法中判断

/**
 * @desc 封装response  支持静态页面以及php页面
 *
 */
void wrap_response(int connfd,char *filename) {
    struct stat sbuf;
    int filefd,phpfd;
    char *php_result;
    char *srcp;
    char response[MAXLINE],filetype[MAXLINE];
    if(stat(filename,&sbuf) < 0) {
        error_response(connfd);
        exit(1);
    }else {
        

如果不存在,我们就会让他走一个error_sponse方法,这里就会包装response头信息以及文件

/**
 * @desc 404页面的response拼接
 *
 */
void error_response(int connfd) {
    struct stat sbuf;
    int filefd;
    char *srcp;
    char error_body[MAXLINE],response[MAXLINE];
    char filename[] = "./404.html";
    
    stat(filename,&sbuf);
    filefd = open(filename,O_RDONLY);
    
    sprintf(response, "HTTP/1.1 404 Not found\r\n");
    sprintf(response, "%sServer: Pengge Web Server\r\n",response);
    sprintf(response, "%sConnection: close\r\n",response);
    sprintf(response, "%sContent-length: %lld\r\n",response,sbuf.st_size);
    sprintf(response, "%sContent-type: text/html\r\n\r\n",response);
    Write(connfd, response, strlen(response));
    printf("Response headers:\n");
    srcp = mmap(0, sbuf.st_size, PROT_READ, MAP_PRIVATE, filefd, 0);
    Close(filefd);
    //清空srcp空间
    Write(connfd, srcp, sbuf.st_size);
    munmap(srcp, sbuf.st_size);

}

这个时候重新打开浏览器,运行

http://localhost:8000/index1.php

查看浏览器是不是有这样的报错界面了

用C一步步开发web服务器(4)_第3张图片

到此,整个webserver到此结束了,撒花


最后,留给自己以及读者讨论的内容有以下几点

  • 如何支持像nginx一样的配置文件
  • nginx中的epoll 模式能否支持
  • 同样是nginx中的功能,如负载均衡,动静分离该怎么在配置文件中配置,并实现
  • ...

最后献上我的代码,我传到我的github上了。多谢欣赏,希望能对大家有帮助原文章链接

你可能感兴趣的:(用C一步步开发web服务器(4))