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

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


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

http://localhost:8000/index.php

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

<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>鵬哥的第一個(gè)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)頁(yè)面以及php頁(yè)面
 *
 */
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)頁(yè)面輸出
        }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);
        }
    }
}

這里有個(gè)

php_cgi(filename, connfd);

這個(gè)方法痢甘,這個(gè)就是執(zhí)行php腳本輸出到頁(yè)面的方法,我們可以這樣寫

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錯(cuò)誤界面的開發(fā)了块仆,
瀏覽器輸入

http://localhost:8000/index1.php

1.因?yàn)椴淮嬖谶@個(gè)頁(yè)面构蹬,所以我們需要像nginx一樣,創(chuàng)建一個(gè)404頁(yè)面

<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)頁(yè)面以及php頁(yè)面
 *
 */
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 {
        

如果不存在悔据,我們就會(huì)讓他走一個(gè)error_sponse方法庄敛,這里就會(huì)包裝response頭信息以及文件

/**
 * @desc 404頁(yè)面的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);

}

這個(gè)時(shí)候重新打開瀏覽器,運(yùn)行

http://localhost:8000/index1.php

查看瀏覽器是不是有這樣的報(bào)錯(cuò)界面了

到此科汗,整個(gè)webserver到此結(jié)束了藻烤,撒花


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

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末早歇,一起剝皮案震驚了整個(gè)濱河市倾芝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌箭跳,老刑警劉巖晨另,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異谱姓,居然都是意外死亡借尿,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門屉来,熙熙樓的掌柜王于貴愁眉苦臉地迎上來路翻,“玉大人,你說我怎么就攤上這事奶躯≈阕” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵嘹黔,是天一觀的道長(zhǎng)账嚎。 經(jīng)常有香客問我莫瞬,道長(zhǎng),這世上最難降的妖魔是什么郭蕉? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任疼邀,我火速辦了婚禮,結(jié)果婚禮上召锈,老公的妹妹穿的比我還像新娘旁振。我一直安慰自己,他們只是感情好涨岁,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布拐袜。 她就那樣靜靜地躺著,像睡著了一般梢薪。 火紅的嫁衣襯著肌膚如雪蹬铺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天秉撇,我揣著相機(jī)與錄音甜攀,去河邊找鬼。 笑死琐馆,一個(gè)胖子當(dāng)著我的面吹牛规阀,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播瘦麸,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼谁撼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了瞎暑?” 一聲冷哼從身側(cè)響起彤敛,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎了赌,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體玄糟,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡勿她,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了阵翎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逢并。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖郭卫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情贰军,我是刑警寧澤玻蝌,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響俯树,放射性物質(zhì)發(fā)生泄漏帘腹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一许饿、第九天 我趴在偏房一處隱蔽的房頂上張望阳欲。 院中可真熱鬧,春花似錦陋率、人聲如沸球化。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)赊窥。三九已至,卻和暖如春狸页,著一層夾襖步出監(jiān)牢的瞬間锨能,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工芍耘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留址遇,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓斋竞,卻偏偏與公主長(zhǎng)得像倔约,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子坝初,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1. Nginx的模塊與工作原理 Nginx由內(nèi)核和模塊組成浸剩,其中,內(nèi)核的設(shè)計(jì)非常微小和簡(jiǎn)潔鳄袍,完成的工作也非常簡(jiǎn)單...
    rosekissyou閱讀 10,215評(píng)論 5 124
  • 更改ip和dnsVi /etc/sysconfig/network-scripts/ifcfg-eth0vi /...
    Xwei_閱讀 1,820評(píng)論 0 3
  • 大家可以教程1绢要,教程2,教程3拗小,教程4中查看之前內(nèi)容重罪。 本來這個(gè)系列告一段落了,但是看到@指尖流年的評(píng)論中提到的關(guān)...
    jamespengge閱讀 1,256評(píng)論 2 4
  • 1.ngnix介紹 ngnix www服務(wù)軟件 俄羅斯人開發(fā) 開源 性能很高 本身是一款靜態(tài)WWW軟件 靜態(tài)小文件...
    逗比punk閱讀 2,095評(píng)論 1 6
  • 第一章 Nginx簡(jiǎn)介 Nginx是什么 沒有聽過Nginx哀九?那么一定聽過它的“同行”Apache吧剿配!Ngi...
    JokerW閱讀 32,685評(píng)論 24 1,002