用C一步步開發(fā)web服務(wù)器(4)

教程1教程2,教程3的帶領(lǐng)下,大家肯定迫不及待進(jìn)行教程4的開發(fā)了吧,這一章節(jié),我們要完成現(xiàn)在這個webserver的所有功能,支持php動態(tài)頁面以及報錯404頁面的開發(fā),先展示下最終實現(xiàn)的界面


話不多說,先支持PHP再說
1.瀏覽器輸入

http://localhost:8000/index.php

可見,他是指向當(dāng)前目錄下的index.php文件,所以先在這個目錄下創(chuàng)建文件

<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>鵬哥的第一個web服務(wù)器</title>
</head>
<body>
<?php
$array = array(
    "id" => "1",
    "name"=> "pengge",
    "aaa" => "sdsdd",
    "yes" => "sdsdfsfsff"
);
echo "<pre>";
var_dump($array);
?>
</body>
</html>

2.順著教程3的思路,解析filename的文件名,發(fā)現(xiàn)他是.php文件,所以我們不能直接文件讀取他的內(nèi)容,我們需要通過php腳本執(zhí)行該文件內(nèi)容,然后輸出到瀏覽器上
重寫wrap_response方法,使其支持php

/**
 * @desc 封裝response  支持靜態(tài)頁面以及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);
        
        //打開文件并將其寫入內(nèi)存,并由瀏覽器展示
        filefd = open(filename,O_RDONLY);
        //走php腳本執(zhí)行輸出
        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);
        //走靜態(tài)頁面輸出
        }else {
            
            //拼接靜態(tài)文件的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);

這個方法,這個就是執(zhí)行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


接下來,我們要進(jìn)行404錯誤界面的開發(fā)了,
瀏覽器輸入

http://localhost:8000/index1.php

1.因為不存在這個頁面,所以我們需要像nginx一樣,創(chuàng)建一個404頁面

<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>Pengge Server/1.0</center>
</body>
</html>

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

/**
 * @desc 封裝response  支持靜態(tài)頁面以及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

查看瀏覽器是不是有這樣的報錯界面了

到此,整個webserver到此結(jié)束了,撒花


最后,留給自己以及讀者討論的內(nèi)容有以下幾點

  • 如何支持像nginx一樣的配置文件
  • nginx中的epoll 模式能否支持
  • 同樣是nginx中的功能,如負(fù)載均衡,動靜分離該怎么在配置文件中配置,并實現(xiàn)
  • ...

最后獻(xiàn)上我的代碼,我傳到我的github上了。多謝欣賞,希望能對大家有幫助原文章鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 更改ip和dnsVi /etc/sysconfig/network-scripts/ifcfg-eth0vi /...
    Xwei_閱讀 2,052評論 0 3
  • 大家可以教程1,教程2,教程3,教程4中查看之前內(nèi)容。 本來這個系列告一段落了,但是看到@指尖流年的評論中提到的關(guān)...
    jamespengge閱讀 1,393評論 2 4
  • 1.ngnix介紹 ngnix www服務(wù)軟件 俄羅斯人開發(fā) 開源 性能很高 本身是一款靜態(tài)WWW軟件 靜態(tài)小文件...
    逗比punk閱讀 2,250評論 1 6
  • 第一章 Nginx簡介 Nginx是什么 沒有聽過Nginx?那么一定聽過它的“同行”Apache吧!Ngi...
    JokerW閱讀 33,029評論 24 1,002
  • 內(nèi)存 各類存儲區(qū)的邏輯鏈接來自“請叫我hank”簡書.png 各類存儲器的邏輯連接-物理地址對應(yīng)圖來自“請叫我ha...
    handsome5閱讀 422評論 0 0

友情鏈接更多精彩內(nèi)容