麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁(yè) > 編程 > PHP > 正文

PHP內(nèi)核學(xué)習(xí) 深入理解FastCGI

2020-03-22 20:14:58
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
  • |=-----------------------------------------------------------------------=||=------------------------=[ 深入理解FastCGI ]=--------------------------=||=-----------------------------------------------------------------------=||=--------------------------=[  by d4shman  ]=---------------------------=||=-----------------------------------------------------------------------=||=-------------------------=[  May 7, 2014  ]=---------------------------=||=-----------------------------------------------------------------------=|[目錄](méi)0x01 什么是FastCGI0x02 FastCGI的工作流程0x03 PHP中的CGI實(shí)現(xiàn)0x04 參考文獻(xiàn)0x01 什么是FastCGI    CGI全稱(chēng)是“通用網(wǎng)關(guān)接口”( Common Gateway Interface),它可以讓一個(gè)客戶(hù)端從網(wǎng)頁(yè)瀏覽器向執(zhí)行在web服務(wù)器上的程序請(qǐng)求數(shù)據(jù)。CGI描述了客戶(hù)端和這個(gè)程序之間傳遞數(shù)據(jù)的一種標(biāo)準(zhǔn)。    FastCGI是web服務(wù)器和處理程序之間通訊的一種協(xié)議, 是CGI的一種改進(jìn)方案, FastCGI像是一個(gè)常駐(long live)型的CGI, 它可以一直執(zhí)行,在請(qǐng)求到達(dá)時(shí)不會(huì)花費(fèi)時(shí)間去fork一個(gè)進(jìn)程來(lái)處理(這是CGI最為人詬病的fork-and-execute模式)。    CGI程序反復(fù)加載是CGI性能低下的主要原因,F(xiàn)astCGI將CGI解釋器進(jìn)程保持在內(nèi)存內(nèi)中,以此獲得較高的性能。同時(shí),F(xiàn)astCGI還支持分布式計(jì)算,也就是說(shuō),Web Server和FastCGI可以部署在不同的服務(wù)器上。0x02 FastCGI的工作流程    1.Web server啟動(dòng)時(shí)載入FastCGI進(jìn)程管理器(Apache Module、IIS ISAPI等)    2.FastCGI進(jìn)程管理器自身初始化,啟動(dòng)多個(gè)CGI解釋器進(jìn)程php-cgi并等待來(lái)自      Web Server的連接。    3.當(dāng)客戶(hù)端的請(qǐng)求到達(dá)Web Server時(shí),F(xiàn)astCGI選擇并連接到一個(gè)CGI解釋器。      Web server將CGIhtml' target='_blank'>環(huán)境變量和標(biāo)準(zhǔn)輸入發(fā)送到FastCGI子進(jìn)程php-cgi。    4.FastCGI子進(jìn)程完成處理后將標(biāo)準(zhǔn)輸出和錯(cuò)誤信息從同一連接返回Web Server。      php-cgi關(guān)閉本次連接并等待下次連接。	  0x03 PHP中的CGI實(shí)現(xiàn)    PHP中的CGI實(shí)現(xiàn)了FastCGI協(xié)議,是一個(gè)TCP或UDP協(xié)議的服務(wù)器接受來(lái)自Web服務(wù)器的請(qǐng)求,當(dāng)啟動(dòng)時(shí)創(chuàng)建TCP/UDP協(xié)議的服務(wù)器socket監(jiān)聽(tīng),并接受相關(guān)請(qǐng)求進(jìn)行處理。隨后就進(jìn)入了PHP的生命周期:模塊初始化,sapi初始化,處理PHP請(qǐng)求,模塊關(guān)閉,sapi關(guān)閉。以上構(gòu)成了PHP中CGI的生命周期。    以TCP為例,在TCP的服務(wù)端,一般會(huì)執(zhí)行這樣的幾個(gè)操作步驟:        1.調(diào)用socket函數(shù)創(chuàng)建一個(gè)TCP用的流式套接字    2.調(diào)用bind函數(shù)將服務(wù)器的本地地址與前面創(chuàng)建的套接字綁定    3.調(diào)用listen函數(shù)監(jiān)聽(tīng)新創(chuàng)建的套接字,等待客戶(hù)端發(fā)起的連接請(qǐng)求    4.服務(wù)器進(jìn)程調(diào)用accept函數(shù)進(jìn)入阻塞狀態(tài),知道有客戶(hù)進(jìn)程調(diào)用connect函數(shù)建      立連接    5.當(dāng)連接建立后,服務(wù)器調(diào)用read_stream函數(shù)讀取客戶(hù)端的請(qǐng)求    6.處理完數(shù)據(jù)后,服務(wù)器調(diào)用write函數(shù)向客戶(hù)端發(fā)送應(yīng)答        <!-------------- 這就是活生生的socket通信啊 --------------->         下面從PHP源碼來(lái)看這個(gè)過(guò)程:    (以下代碼我只保留了關(guān)鍵部分,完整代碼請(qǐng)自行查看PHP源碼)	    1.socket的創(chuàng)建、綁定和監(jiān)聽(tīng)(在源碼的sapi/cgi/fastcgi.c中)	    /* Create, bind socket and start listen on it */    if ((listen_socket = socket(sa.sa.sa_family, SOCK_STREAM, 0)) < 0 ||    #ifdef SO_REUSEADDR        setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) < 0 ||    #endif        bind(listen_socket, (struct sockaddr *) &sa, sock_len) < 0 ||        listen(listen_socket, backlog) < 0) {            fprintf(stderr, "Cannot bind/listen socket - [%d] %s.",errno, strerror(errno));        return -1;    }	    2.當(dāng)服務(wù)端初始化完成后,進(jìn)程調(diào)用accept函數(shù)進(jìn)入阻塞狀態(tài),在main函數(shù)中我們看到如下代碼:	    while (parent) {        do {            pid = fork();   //  fork出新的子進(jìn)程            switch (pid) {            case 0:                 parent = 0;                    /* don't catch our signals */                sigaction(SIGTERM, &old_term, 0);   //  終止信號(hào)                sigaction(SIGQUIT, &old_quit, 0);   //  終端退出符                sigaction(SIGINT,  &old_int,  0);   //  終端中斷符                break;                ...                default:                /* Fine */                running++;                break;        } while (parent && (running < children));    	/* 調(diào)用fcgi_accept_request接受請(qǐng)求 */        while (!fastcgi || fcgi_accept_request(&request) >= 0) {    		SG(server_context) = (void *) &request;    		init_request_info(TSRMLS_C);    		CG(interactive) = 0;        }    }	    3.調(diào)用read函數(shù)讀取客戶(hù)端請(qǐng)求:	    static int fcgi_read_request(fcgi_request *req)    {        fcgi_header hdr;        int len, padding;        unsigned char buf[FCGI_MAX_LENGTH+8];                req->keep = 0;        req->closed = 0;        req->in_len = 0;        req->out_hdr = NULL;        req->out_pos = req->out_buf;        req->has_env = 1;        /*調(diào)用sage_read讀取fcgi_request類(lèi)型的數(shù)據(jù)req*/        if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||            hdr.version < FCGI_VERSION_1) {            return 0;        }    }        在請(qǐng)求初始化完成,讀取請(qǐng)求完畢后,就該處理請(qǐng)求的PHP文件了。 假設(shè)此次請(qǐng)求為PHP_MODE_STANDARD則會(huì)調(diào)用php_execute_script執(zhí)行PHP文件。在此函數(shù)中它先初始化此文件相關(guān)的一些內(nèi)容,然后再調(diào)用zend_execute_scripts函數(shù),對(duì)PHP文件進(jìn)行詞法分析和語(yǔ)法分析,生成中間代碼, 并執(zhí)行zend_execute函數(shù),從而執(zhí)行這些中間代碼。	    4.fastCGI處理完成	    int fcgi_finish_request(fcgi_request *req, int force_close)    {        int ret = 1;            if (req->fd >= 0) {            if (!req->closed) {                ret = fcgi_flush(req, 1);                req->closed = 1;            }            fcgi_close(req, force_close, 1);        }        return ret;    }    如上,當(dāng)socket處于打開(kāi)狀態(tài)(reg->fd >= 0),并且請(qǐng)求未關(guān)閉,則會(huì)將執(zhí)行后的結(jié)果刷到客戶(hù)端,并將請(qǐng)求的關(guān)閉設(shè)置為真。 將數(shù)據(jù)刷到客戶(hù)端的程序調(diào)用的是fcgi_flush函數(shù)。在此函數(shù)中,關(guān)鍵是在于答應(yīng)頭的構(gòu)造和寫(xiě)操作。 程序的寫(xiě)操作是調(diào)用的safe_write函數(shù),而safe_write函數(shù)中對(duì)于最終的寫(xiě)操作針對(duì)win和linux環(huán)境做了區(qū)分,在Win32下,如果是TCP連接則用send函數(shù),如果是非TCP則和非win環(huán)境一樣使用write函數(shù)。如下代碼:        static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t count)    {        int    ret;        size_t n = 0;            do {            errno = 0;        #ifdef _WIN32 /*win32環(huán)境*/            if (!req->tcp) { /*非TCP連接,調(diào)用write函數(shù)*/                ret = write(req->fd, ((char*)buf)+n, count-n);            } else {         /*TCP連接,調(diào)用send函數(shù)*/                ret = send(req->fd, ((char*)buf)+n, count-n, 0);                if (ret <= 0) {                    errno = WSAGetLastError();                }            }        #else  /*其他環(huán)境, 調(diào)用write函數(shù)*/            ret = write(req->fd, ((char*)buf)+n, count-n);        #endif            if (ret > 0) {                n += ret;            } else if (ret <= 0 && errno != 0 && errno != EINTR) {                return ret;            }        } while (n != count);        return n;    }    以上就是基于TCP連接的PHP FastCGI的實(shí)現(xiàn)過(guò)程。	0x04 參考文獻(xiàn)《深入理解PHP內(nèi)核》
    PHP編程

    鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。

  • 發(fā)表評(píng)論 共有條評(píng)論
    用戶(hù)名: 密碼:
    驗(yàn)證碼: 匿名發(fā)表
    主站蜘蛛池模板: 国产精品久久久久久久久久久久久久久久 | 亚洲男人的天堂在线视频 | 九色 在线 | 在线区| 精品久久久久久久久久中文字幕 | 国产69精品久久99不卡免费版 | 亚洲国产高清一区 | 91福利免费视频 | 九九热视频免费观看 | 国产高潮好爽受不了了夜色 | 国产精品成人久久 | 国产在线导航 | 久久久久久久久久网 | 国产精品久久久久久久不卡 | 国产欧美在线观看不卡一 | 久久久久久艹 | 黄色成人在线播放 | 三级国产三级在线 | 日本黄色a视频 | 宅男噜噜噜66国产免费观看 | 色人阁导航| 妇女毛片 | 亚洲综合一区在线观看 | 欧美一级性 | 中文字幕在线视频日本 | 青青草成人免费视频在线 | 调教小男生抽打尿孔嗯啊视频 | 一本一本久久a久久精品综合小说 | 天堂精品久久 | 日日鲁夜夜视频热线播放 | 亚洲成人福利在线观看 | 高潮激情aaaaa免费看 | 中国免费一级毛片 | 成人福利视频在线观看 | www.99久| 亚洲午夜免费 | 91福利免费视频 | 91懂色| 日本欧美中文字幕 | 视频一区二区三区在线播放 | 爱爱视频天天干 |