溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Swoole與HTTP的使用介紹

發(fā)布時(shí)間:2021-03-08 14:08:09 來(lái)源:億速云 閱讀:547 作者:TREX 欄目:編程語(yǔ)言

這篇文章主要講解了“Swoole與HTTP的使用介紹”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Swoole與HTTP的使用介紹”吧!

Swoole與HTTP的使用介紹

目標(biāo)

  • 了解swoole的http_server的使用

  • 了解swoole的tcp服務(wù)開發(fā)

  • 實(shí)際項(xiàng)目中問(wèn)題如粘包處理、代理熱更新、用戶驗(yàn)證等。

  • swoole與現(xiàn)有框架結(jié)合

推薦(免費(fèi)):swoole

風(fēng)格

  • 偏基礎(chǔ)重代碼

環(huán)境

  • PHP版本:

  • Swoole版本:https://github.com/swoole/swoole-src

  • zphp開發(fā)框架:https://github.com/shenzhe/zphp

HTTP Server

  • 靜態(tài)文件處理

  • 動(dòng)態(tài)請(qǐng)求與框架結(jié)合

# 查看SWOOLE版本
$ php -r 'echo SWOOLE_VERSION;'
4.3.1

基礎(chǔ)概念

HTTP報(bào)文

關(guān)于HTTP請(qǐng)求報(bào)文的組成結(jié)構(gòu)

Swoole與HTTP的使用介紹

HTTP請(qǐng)求報(bào)文結(jié)構(gòu)

POST /search HTTP/1.1  
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, 
application/msword, application/x-silverlight, application/x-shockwave-flash, */*  
Referer: http://www.google.cn/  
Accept-Language: zh-cn  
Accept-Encoding: gzip, deflate  
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; TheWorld)  
Host: www.google.cn 
Connection: Keep-Alive  
Cookie: PREF=ID=80a06da87be9ae3c:U=f7167333e2c3b714:NW=1:TM=1261551909:LM=1261551917:S=ybYcq2wpfefs4V9g; 
NID=31=ojj8d-IygaEtSxLgaJmqSjVhCspkviJrB6omjamNrSm8lZhKy_yMfO2M4QMRKcH1g0iQv9u-2hfBW7bUFwVh7pGaRUb0RnHcJU37y-
FxlRugatx63JLv7CWMD6UB_O_r  

hl=zh-CN&source=hp&q=domety

關(guān)于HTTP響應(yīng)報(bào)文的組成結(jié)構(gòu)

Swoole與HTTP的使用介紹

HTTP響應(yīng)報(bào)文結(jié)構(gòu)

HTTP/1.1 200 OK
Date: Mon, 23 May 2005 22:38:34 GMT
Content-Type: text/html; charset=UTF-8
Content-Encoding: UTF-8
Content-Length: 138
Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux)
ETag: "3f80f-1b6-3e1cb03b"
Accept-Ranges: bytes
Connection: close

創(chuàng)建HTTP服務(wù)器

Swoole在1.7.7版本后內(nèi)置HTTP服務(wù)器,可創(chuàng)建一個(gè)異步非阻塞多進(jìn)程的HTTP服務(wù)器。Swoole的HTTP服務(wù)器對(duì)HTTP協(xié)議支持的并不完整,建議僅作為應(yīng)用服務(wù)器,并在前端增加Nginx作為代理。

因?yàn)镾woole是在CLI命令行中執(zhí)行的,在傳統(tǒng)的NGINX+FastCGI模式下很多rootshell是無(wú)法執(zhí)行的,而使用Swoole服務(wù)器就能很好的控制rsync、git、svn等。

使用Swoole的API,構(gòu)建HTTP服務(wù)器需要4個(gè)步驟

  1. 創(chuàng)建Server對(duì)象

  2. 設(shè)置運(yùn)行時(shí)參數(shù)

  3. 注冊(cè)事件回調(diào)函數(shù)

  4. 啟動(dòng)服務(wù)器

# 創(chuàng)建應(yīng)用
$ mkdir test && cd test

# 創(chuàng)建并編輯服務(wù)器文件
$ vim server.php
<?php

//創(chuàng)建HTTP服務(wù)器對(duì)象
$host = "0.0.0.0";
$port = 9501;
$server = new swoole_http_server($host, $port);
var_dump($server);

//設(shè)置服務(wù)器運(yùn)行參數(shù)
$configs = [];
$configs["worker_num"] = 2;//設(shè)置Worker工作進(jìn)程數(shù)量
$configs["daemonize"] = 0;//設(shè)置是否已后臺(tái)守護(hù)進(jìn)程運(yùn)行
$server->set($configs);

//注冊(cè)監(jiān)聽(tīng)客戶端HTTP請(qǐng)求回調(diào)事件
$server->on("request", function(swoole_http_request $request, swoole_http_response $response) use($server){
    var_dump($request);
    var_dump($response);
    
    //獲取客戶端文件描述符
    $fd = $request->fd;
    if(!empty($fd)){
        //獲取連接信息
        $clientinfo = $server->getClientInfo($fd);
        var_dump($clientinfo);
        //獲取收包時(shí)間
        var_dump($clientinfo["last_time"]);
    }

    //響應(yīng)客戶端HTTP請(qǐng)求
    $response->write("success");//向客戶端寫入響應(yīng)數(shù)據(jù)
    $response->end();//瀏覽器中輸出結(jié)果
});

//啟動(dòng)服務(wù)器
$server->start();
# 使用PHP-CLI運(yùn)行服務(wù)器腳本
$ php server.php

# 使用CURL向HTTP服務(wù)器發(fā)送請(qǐng)求測(cè)試
$ curl 127.0.0.1:9501

使用注意

  • echo、var_dump、print_r的內(nèi)容是在服務(wù)器中輸出的

  • 瀏覽器中輸出需要使用$rp->end(string $contents)end()方法只能調(diào)用一次。

  • 如果需要多次先客戶端發(fā)送消息可使用$rp->write(string $content)方法

  • 完整的HTTP協(xié)議請(qǐng)求會(huì)被解析并封裝在swoole_http_request對(duì)象中

  • 所有的HTTP協(xié)議響應(yīng)會(huì)通過(guò)swoole_http_response對(duì)象進(jìn)行封裝并發(fā)送

HTTP服務(wù)器的本質(zhì)

由于swoole_http_server是基于swoole_server的,所以swoole_server下的方法在swoole_http_server中都可以使用,只是swoole_http_server只能被客戶端喚起。簡(jiǎn)單來(lái)說(shuō),swoole_http_server是基于swoole_server加上HTTP協(xié)議,再加上requestresponse類庫(kù)去實(shí)現(xiàn)請(qǐng)求數(shù)據(jù)和獲取數(shù)據(jù)。與PHP-FPM不同的是,Web服務(wù)器收到請(qǐng)求后會(huì)傳遞給Swoole的HTTP服務(wù)器,直接返回請(qǐng)求。

Swoole與HTTP的使用介紹

swoole_http_server

Http\Server

Swoole\HTTP\Server繼承自Server,是一個(gè)HTTP服務(wù)器實(shí)現(xiàn),支持同步與有異步兩種模式。無(wú)論是同步模式還是異步模式,HTTP服務(wù)器都可以維持大量的TCP客戶端連接,同步與異步僅僅提現(xiàn)在對(duì)請(qǐng)求的處理方式。

  • 同步模式

同步模式等同于Nginx+PHP-FPM/Apache,需要設(shè)置大量Worker工作進(jìn)程來(lái)完成并發(fā)請(qǐng)求處理,Worker工作進(jìn)程可以使用同步阻塞IO,編程方式與普通的PHP的Web程序完全一致。與PHP-FPM/Apache不同的是,客戶端連接并不會(huì)獨(dú)占進(jìn)程,服務(wù)器依然可以應(yīng)對(duì)大量并發(fā)連接。

  • 異步模式

異步模式下整個(gè)HTTP服務(wù)器是異步非阻塞的,服務(wù)器可以應(yīng)答大規(guī)模的并發(fā)連接和并發(fā)請(qǐng)求,編程方式需要完全使用異步API,如MySQL、Redis、HTTP客戶端、file_get_contents、sleep等阻塞IO操作必須切換為異步方式,如異步Client、Event、Timer等API。

查看HTTP服務(wù)器實(shí)例對(duì)象

var_dump($server);
object(Swoole\Connection\Iterator)#2 (0) {
  ["host"]=>string(7) "0.0.0.0"
  ["port"]=>int(9501)
  ["type"]=>int(1)
  ["mode"]=>int(2)
  ["ports"]=>
  array(1) {
    [0]=>
    object(Swoole\Server\Port)#3 (16) {
      ["onConnect":"Swoole\Server\Port":private]=>NULL
      ["onReceive":"Swoole\Server\Port":private]=>NULL
      ["onClose":"Swoole\Server\Port":private]=>NULL
      ["onPacket":"Swoole\Server\Port":private]=>NULL
      ["onBufferFull":"Swoole\Server\Port":private]=>NULL
      ["onBufferEmpty":"Swoole\Server\Port":private]=>NULL
      ["onRequest":"Swoole\Server\Port":private]=>NULL
      ["onHandShake":"Swoole\Server\Port":private]=>NULL
      ["onOpen":"Swoole\Server\Port":private]=>NULL
      ["onMessage":"Swoole\Server\Port":private]=>NULL
      ["host"]=>string(7) "0.0.0.0"
      ["port"]=>int(9501)
      ["type"]=>int(1)
      ["sock"]=>int(4)
      ["setting"]=>NULL
      ["connections"]=>object(Swoole\Connection\Iterator)#4 (0) {
      }
    }
  }
  ["master_pid"]=>int(0)
  ["manager_pid"]=>int(0)
  ["worker_id"]=>int(-1)
  ["taskworker"]=>bool(false)
  ["worker_pid"]=>int(0)
  ["onRequest":"Swoole\Http\Server":private]=>NULL
  ["onHandshake":"Swoole\Http\Server":private]=>NULL
}

配置選項(xiàng)

文件上傳upload_tmp_dir

HTTP服務(wù)器支持大文件上傳,但由于Swoole底層的限制,文件內(nèi)容是存放在內(nèi)存中的,因此如果并發(fā)上傳大量文件可能會(huì)導(dǎo)致內(nèi)存占用量過(guò)大的問(wèn)題。

可以修改upload_tmp_dir選項(xiàng)用于配置上傳文件的臨時(shí)目錄,需要注意是目錄文件夾的名稱最大長(zhǎng)度不得超過(guò)220個(gè)字節(jié)。

$configs = [];
$configs["upload_tmp_dir"] = "/data/uploads/";
$server->set($configs);

POST解析http_parse_post

可通過(guò)修改http_parse_post配置項(xiàng)用來(lái)設(shè)置表單POST提交后是否解析,若設(shè)置為true則表示會(huì)自動(dòng)將Content-Type內(nèi)容類型為x-www-urlencode的請(qǐng)求包體解析到 POST 數(shù)組,若設(shè)置為false則表示將會(huì)關(guān)閉 POST解析。

$configs = [];
$configs["http_parse_post"] = true;
$server->set($configs);

POST尺寸 package_max_length

默認(rèn)情況下,表單上傳或POST提交2MB的數(shù)據(jù)的限制,可通過(guò)修改package_max_length選項(xiàng)調(diào)整POST尺寸大小。

$configs = [];
$configs["package_max_length"] = 2*1024;
$server->set($configs);

解析Cookiehttp_parse_cookie

通過(guò)修改http_parse_cookie配置項(xiàng)可以開啟或關(guān)閉Cookie解析,關(guān)閉后將會(huì)在Header頭信息學(xué)中保留未經(jīng)處理的原始Cookies信息。

$configs = [];
$configs["http_parse_cookie"] = true;
$server->set($configs);
文件壓縮http_compression

http_compression適用于Swoole4.1.0+版本,用于啟用或關(guān)閉對(duì)HTTP信息的壓縮,默認(rèn)為開啟狀態(tài)。

由于http-chunk不支持分段獨(dú)立壓縮,因此默認(rèn)已強(qiáng)制關(guān)閉了壓縮功能。

$configs = [];
$configs["http_compression"] = false;
$server->set($configs);

目前HTTP支持gzip、br(需google brotli庫(kù)支持)、deflate三種壓縮格式,Swoole底層會(huì)根據(jù)客戶端瀏覽器傳入的Accept-Encoding頭信息自動(dòng)選擇壓縮方式。

壓縮級(jí)別http_compression_level

http_compression_level選項(xiàng)用于配置壓縮的級(jí)別,壓縮級(jí)別越高壓縮后體積越小,同時(shí)也會(huì)越占用CPU。

$configs = [];
$configs["http_compression_level"] = 1;
$server->set($configs);
靜態(tài)根目錄document_root

document_root選項(xiàng)適用于Swoole1.9.17+版本,用于配置靜態(tài)文件的根目錄,該功能由于較為簡(jiǎn)易不推薦在公網(wǎng)環(huán)境下直接使用,常于enable_static_handler選項(xiàng)配合使用。

如果設(shè)置document_rootenable_static_handler = true后,Swoole底層收到HTTP請(qǐng)求時(shí)會(huì)先判斷document_root的路徑下是否存在某靜態(tài)文件,如果存在會(huì)直接發(fā)送內(nèi)容給客戶端,并不再調(diào)用onRequest函數(shù)。

這里需要注意的時(shí),在使用靜態(tài)文件處理特性時(shí),應(yīng)當(dāng)將動(dòng)態(tài)PHP代碼于靜態(tài)文件進(jìn)行隔離,靜態(tài)文件應(yīng)存放到特定的目錄下。

$configs = [];
$configs["document_root"] = "/app";
$server->set($configs);
靜態(tài)處理 enable_static_handler

enable_static_handler選項(xiàng)用于開啟或關(guān)閉靜態(tài)文件請(qǐng)求處理功能,常配合document_root選項(xiàng)使用。

$configs = [];
$configs["enable_static_handler"] = true;
$server->set($configs);
靜態(tài)處理器路徑static_handler_locations

static_handler_location選項(xiàng)適用于Swoole4.4.0+版本,用于設(shè)置靜態(tài)處理器的路徑,類型為數(shù)組,默認(rèn)不啟用。

靜態(tài)處理器類似于Nginx的location指令,可以指定一個(gè)或多個(gè)路徑為靜態(tài)路徑。只有URL在指定路徑下才會(huì)啟用靜態(tài)問(wèn)而建處理器,否則會(huì)視為動(dòng)態(tài)請(qǐng)求。location選項(xiàng)必須以/開頭并支持多級(jí)路徑,如/app/images。

當(dāng)啟用static_handler_locations選項(xiàng)后,如果請(qǐng)求對(duì)應(yīng)的文件不存在,將直接會(huì)返回404錯(cuò)誤。

$configs = [];
$configs["static_handler_locations"] = ["/static", "/public/assets"];
$server->set($configs);
設(shè)置代理

由于swoole_http_server對(duì)HTTP協(xié)議支持的并不完整,建議僅僅作為應(yīng)用服務(wù)器,并在前端增加Nginx作為反向代理。

操作前需要修改服務(wù)器的運(yùn)行參數(shù),設(shè)置enable_static_handletrue后,底層收到HTTP請(qǐng)求會(huì)像判斷document_root路徑下是否存在目標(biāo)文件,若存在則會(huì)直接發(fā)送文件給客戶端,不再觸發(fā)onRequest回調(diào)。

  1. 設(shè)置服務(wù)器運(yùn)行時(shí)環(huán)境

$ vim server.php
$configs = [];
$configs["enable_static_handler"] =  true;
$configs["document_root"] = "/test";
$server->set($configs);
  1. 設(shè)置Nginx反向代理配置

例如:設(shè)置Nginx反向代理127.0.0.1:9501

$ vim /usr/local/nginx/conf/nginx.conf
http {
    include       mime.types;
    default_type  application/octet-stream;
    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';
    #access_log  logs/access.log  main;
    sendfile        on;
    #tcp_nopush     on;
    #keepalive_timeout  0;
    keepalive_timeout  65;
    #gzip  on;
        upstream swoole{
                server 127.0.0.1:9501;
                keepalive 4;
        }
    server {
        listen       80;
        server_name  www.swoole.com;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / {
            proxy_pass http://swoole;
            proxy_set_header Connection "";
            proxy_http_version 1.1;
            root   html;
            index  index.html index.htm;
        }
        #error_page  404              /404.html;
        # redirect server error pages to the static page /50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
}

Nginx+Swoole的組合中Nginx反向代理的配置

server {
    root /data/wwwroot/;
    server_name local.swoole.com;

    location / {
        proxy_http_version 1.1;
        proxy_set_header Connection "keep-alive";
        proxy_set_header X-Real-IP $remote_addr;
        if (!-e $request_filename) {
             proxy_pass http://127.0.0.1:9501;
        }
    }
}

請(qǐng)求對(duì)象

swoole_http_request請(qǐng)求對(duì)象保存了HTTP客戶端請(qǐng)求的相關(guān)信息,包括GET、POST、COOKIEHeader等,請(qǐng)求對(duì)象$request銷毀時(shí)會(huì)自動(dòng)刪除上傳的臨時(shí)文件,不要使用&符號(hào)引用$request請(qǐng)求對(duì)象。

var_dump($request);

object(Swoole\Http\Request)#6 (10) {
  ["fd"]=>int(1)
  ["streamId"]=>int(0)
  ["header"]=>array(3) {
    ["host"]=>string(14) "127.0.0.1:9501"
    ["user-agent"]=>string(11) "curl/7.52.1"
    ["accept"]=>string(3) "*/*"
  }
  ["server"]=>array(10) {
    ["request_method"]=>string(3) "GET"
    ["request_uri"]=>string(1) "/"
    ["path_info"]=>string(1) "/"
    ["request_time"]=>int(1561689532)
    ["request_time_float"]=>float(1561689533.0563)
    ["server_port"]=>int(9501)
    ["remote_port"]=>int(51188)
    ["remote_addr"]=>string(9) "127.0.0.1"
    ["master_time"]=>int(1561689532)
    ["server_protocol"]=>string(8) "HTTP/1.1"
  }
  ["request"]=>NULL
  ["cookie"]=>NULL
  ["get"]=>NULL
  ["files"]=>NULL
  ["post"]=>NULL
  ["tmpfiles"]=>NULL
}
Http\Request->$header

HTTP請(qǐng)求的頭部信息,類型為數(shù)組,所有的鍵名均為小寫。

$host = $request->header["host"];
$accept = $request->header["accept"];

Http\Request->$server

HTTP請(qǐng)求相關(guān)的服務(wù)器信息,相當(dāng)于PHP的$_SERVER全局?jǐn)?shù)組,包含了HTTP請(qǐng)求的方法、URL路徑、客戶端IP等信息。服務(wù)器信息為關(guān)聯(lián)數(shù)組,數(shù)組中的鍵名全部小寫,并且與PHP的$_SERVER數(shù)組保持一致。

$request_method = $request->server["request_method"];
$request_time = $request->server["request_time"];
$request_uri = $request->server["request_uri"];

請(qǐng)求路徑

當(dāng)Google的Chrome瀏覽器訪問(wèn)服務(wù)器是會(huì)產(chǎn)生兩次請(qǐng)求,這是因?yàn)镃hrome會(huì)自動(dòng)請(qǐng)求一次favicon.ico文件,所以服務(wù)器會(huì)收到兩個(gè)HTTP請(qǐng)求,通過(guò)打印$request->server["request_uri"]可以查看到請(qǐng)求URL路徑。如果需要屏蔽掉對(duì)favicon.ico的請(qǐng)求,可采用以下方式。

$uri = $request->server["request_uri"];
if($uri == "/favicon.icon")
{
  $respoonse->status(404);
  $response->end();
}

收包時(shí)間

request_time請(qǐng)求時(shí)間是在Worker工作進(jìn)程中設(shè)置的,在SWOOLE_PROCESS多進(jìn)程模式下存在dispatch分發(fā)的過(guò)程,因此可能會(huì)與實(shí)際收包時(shí)間存在偏差,尤其當(dāng)請(qǐng)求量超過(guò)服務(wù)器處理能力時(shí),有可能滯后于實(shí)際收包時(shí)間。

可通過(guò)Server->getClientInfo()方法獲取last_time以獲取 準(zhǔn)確的收包時(shí)間。

//獲取客戶端文件描述符
$fd = $request->fd;
if(!empty($fd)){
    //獲取連接信息
    $clientinfo = $server->getClientInfo($fd);
    var_dump($clientinfo);
    //獲取收包時(shí)間
    var_dump($clientinfo["last_time"]);
}

客戶端信息

Server->getClientInfo()用于獲取連接的客戶端信息

bool|array Server->getClientInfo(int $fd, int $extraData, bool $ignoreError = false)
  • int $fd 表示客戶端連接文件描述符

  • int $extraData 表示擴(kuò)展信息是保留參數(shù)目前無(wú)任何效果

  • bool $ignoreError 表示是否忽略錯(cuò)誤,若設(shè)置為true表示即使連接關(guān)閉也會(huì)返回連接信息。

如果傳入的$fd客戶端連接文件描述符存在則返回一個(gè)數(shù)組,若不存在或已關(guān)閉則返回false。

array(10) {
  ["server_port"]=>int(9501)
  ["server_fd"]=>int(4)
  ["socket_fd"]=>int(12)
  ["socket_type"]=>int(1)
  ["remote_port"]=>int(51194)
  ["remote_ip"]=>string(9) "127.0.0.1"
  ["reactor_id"]=>int(0)
  ["connect_time"]=>int(1561690606)
  ["last_time"]=>int(1561690606)
  ["close_errno"]=>int(0)
}

Http\Request->$get

HTTP請(qǐng)求的GET參數(shù),相當(dāng)于PHP中的$_GET,格式為鍵值對(duì)的關(guān)聯(lián)數(shù)組。為防止HASH攻擊,GET參數(shù)最大不允許超過(guò)128個(gè)。

$get = $request->get;//獲取HTTP請(qǐng)求的所有GET參數(shù)

HTTP的GET請(qǐng)求只有一個(gè)HTTP Header頭,Swowole底層使用固定大小的內(nèi)存緩沖區(qū)為8K,而且不可修改。如果請(qǐng)求不是正確的HTTP請(qǐng)求,將會(huì)出現(xiàn)錯(cuò)誤,底層會(huì)拋出錯(cuò)誤。

WARN swReactorThead_onReceive_http_request: http header is too long.

Http\Request->$post

HTTP請(qǐng)求攜帶POST參數(shù),格式為鍵值對(duì)的關(guān)聯(lián)數(shù)組,POSTHeader加起來(lái)的尺寸不得超過(guò)package_max_length的設(shè)置,否則會(huì)認(rèn)為是惡意請(qǐng)求,另外POST參數(shù)的個(gè)數(shù)不得超過(guò)128個(gè)。

$post = $request->post;

由于POST文件上傳時(shí)最大尺寸收到package_max_length配置項(xiàng)目的限制,默認(rèn)為2MB,可以調(diào)用swoole_server->set傳入新值修改尺寸。

由于Swoole底層是全內(nèi)存的,因此如果設(shè)置過(guò)大可能會(huì)導(dǎo)致大量并發(fā)請(qǐng)求,將服務(wù)器資源耗盡。

設(shè)置計(jì)算方法:最大內(nèi)存占用 = 最大并發(fā)請(qǐng)求數(shù)量 * package_max_length

當(dāng)使用CURL發(fā)送POST請(qǐng)求時(shí)服務(wù)器端會(huì)超時(shí)

CURL在發(fā)送較大的POST請(qǐng)求時(shí)會(huì)首先發(fā)送一個(gè)100-continue的請(qǐng)求,當(dāng)收到服務(wù)器的回應(yīng)才會(huì)發(fā)送實(shí)際的POST數(shù)據(jù)。然后swoole_http_server并不支持100-continue,因此會(huì)導(dǎo)致CURL請(qǐng)求超時(shí)。解決的辦法時(shí)關(guān)閉CURL的100-continue。

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_POST, 1);//設(shè)置為POST方式
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Exception:"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

Http\Request->$cookie

HTTP請(qǐng)求攜帶的COOKIE信息,格式為鍵值對(duì)的關(guān)聯(lián)數(shù)組。

Http\Request->$files

HTTP請(qǐng)求攜帶的文件上傳信息,類型為以form表單名稱為key鍵名的二維數(shù)組,與PHP原生的$_FILES相同,最大文件尺寸不得超過(guò)package_max_length中設(shè)置的值,不要使用Swoole\Http\Server處理大文件上傳。

$files = $request->files;
var_dump($files);
array(5) {
    [name] => facepalm.jpg
    [type] => image/jpeg
    [tmp_name] => /tmp/swoole.upfile.n3FmFr
    [error] => 0
    [size] => 15476
}
  • name表示瀏覽器上傳時(shí)傳入的文件名稱

  • type表示瀏覽器上傳時(shí)的MIME類型

  • tmp_name 表示瀏覽器上傳的臨時(shí)文件,文件名默認(rèn)以/tmp/swoole.upfile開頭。

  • size表示上傳文件的尺寸

Swoole1.9.10+版本支持is_uploaded_filemove_uploaded_file函數(shù)。當(dāng)HTTP請(qǐng)求對(duì)象$request對(duì)象銷毀時(shí),會(huì)自動(dòng)刪除上傳的臨時(shí)文件。

Http\Request->rawContent()

rawContent表示獲取原始的POST包體,用于非application/x-www-form-urlencode格式的HTTP的POST請(qǐng)求。等同于原生PHP的fopen("php://input"),有時(shí)服務(wù)器不需要解析HTTP的POST請(qǐng)求參數(shù)。

Swoole1.7.18+版本增加了http_parse_post配置用于關(guān)閉或開啟POST數(shù)據(jù)解析。

string HTTP\Request->rawContent();

Http\Request->getData()

getData()方法用于獲取完整的HTTP請(qǐng)求報(bào)文,包括 Http Header和`HTTP Body消息體。

function swoole_http_request_getData() : string

getData需要Swoole1.10.3或Swoole2.1.2或更高的版本。

響應(yīng)對(duì)象

swoole_http_response響應(yīng)對(duì)象是進(jìn)程隔離的,不能跨越進(jìn)程或?qū)ο蟆H绻钱?dāng)前進(jìn)程中,想使用fd文件描述符保存response響應(yīng)對(duì)象、存儲(chǔ)上下文,可使用PHP全局?jǐn)?shù)組變量來(lái)保存。

swoole_http_response響應(yīng)對(duì)象,通過(guò)調(diào)用此對(duì)象的方法實(shí)現(xiàn)HTTP響應(yīng)的發(fā)送,當(dāng)響應(yīng)對(duì)象銷毀時(shí),如果沒(méi)有調(diào)用end發(fā)送HTTP響應(yīng),底層會(huì)自動(dòng)執(zhí)行end方法。不要使用&符號(hào)引用$response對(duì)象。

object(Swoole\Http\Response)#7 (4) {
  ["fd"]=>int(1)
  ["header"]=>NULL
  ["cookie"]=>NULL
  ["trailer"]=>NULL
}

HTTP服務(wù)器Response響應(yīng)對(duì)象,通過(guò)調(diào)過(guò)此對(duì)象的方法,實(shí)現(xiàn)HTTP響應(yīng)發(fā)送。當(dāng)Response對(duì)象銷毀時(shí),如果未調(diào)用則直接調(diào)用end方法,不要使用&符號(hào)引用$response對(duì)象。

Http\Response->header

function Http\Response->header(
  string $key,
  string $value,
  bool $ucworods = true
)

header方法用于設(shè)置HTTP響應(yīng)的Header頭信息,如果設(shè)置失敗返回false,設(shè)置成功則無(wú)返回值。

  • string $key 表示HTTP頭的Key

  • string $value 表示HTTP頭的Value

  • bool $ucwords 表示是否需要對(duì)Key進(jìn)行HTTP約定格式化,默認(rèn)true會(huì)自動(dòng)格式化。

$response->header("Content-Type", "image/jpeg", true);

跨域處理

$origin = $request->header['origin'];

// Access-Control-Allow-Origin 不能使用 *,這樣修改是不支持php版本低于7.0的。
// $response->header('Access-Control-Allow-Origin', '*');
$response->header('Access-Control-Allow-Origin', $origin);
$response->header('Access-Control-Allow-Methods', 'OPTIONS');
$response->header('Access-Control-Allow-Headers', 'x-requested-with,session_id,Content-Type,token,Origin');
$response->header('Access-Control-Max-Age', '86400');
$response->header('Access-Control-Allow-Credentials', 'true');

if ($request->server['request_method'] == 'OPTIONS') {
  $response->status(200);
  $response->end();
  return;
};

Http\Response->cookie

cookie方法用來(lái)設(shè)置HTTP響應(yīng)的Cookie信息,方法參數(shù)與原生PHP的setcookie函數(shù)完全一致。

function  Http\Response->cookie(
  string $key,
  string $value = "", 
  int $expire = 0,
  string $path = "/",
  string $domain = "",
  bool  $secure = false,
  bool $httponly = false
)

Cookie設(shè)置必須在end方法之前方才生效,Swoole底層自動(dòng)會(huì)對(duì)$value進(jìn)行urlencode編碼處理,同時(shí)允許設(shè)置多個(gè)相同的$key的Cookie。

Http\Response->status

swoole_http_response->status(
  int $http_status_code
)

status方法用于發(fā)送HTTP狀態(tài)碼,$http_status_code必須是合法的HTTP狀態(tài)碼,如2xx、3xx、4xx、5xx等,若不是在會(huì)報(bào)錯(cuò),另外status方法也必須在$response->end()之前執(zhí)行方才生效。

  • string $url表示跳轉(zhuǎn)的新地址會(huì)作為HTTP Header頭中的Location選項(xiàng)進(jìn)行發(fā)送

  • int $http_code 表示狀態(tài)碼,默認(rèn)為302臨時(shí)跳轉(zhuǎn),傳入301表示永久跳轉(zhuǎn)。

Http\Response->redirect

redirect方法適用于Swoole2.2.0+版本,用于發(fā)送HTTP跳轉(zhuǎn),調(diào)用后會(huì)自動(dòng)執(zhí)行end方法并發(fā)送結(jié)束響應(yīng)。

function Http\Response->redirect(
  string $url,
  int $http_code = 302
)

例如

$server = new swoole_http_server("0.0.0.0", 9501, SWOOLE_BASE);
$server->on("request", function(swoole_http_request $request, swoole_http_response $response){
  $url = "http://www.baidu.com";
  $response->redirect($url, 301);
});
$server->start();

Http\Response->write

write方法用于啟用HTTP的chunk分段以向?yàn)g覽器發(fā)送相應(yīng)的內(nèi)容,使用write分段發(fā)送數(shù)據(jù)后end方法將不再接收任何參數(shù),調(diào)用end方法后會(huì)發(fā)送一個(gè)長(zhǎng)度為0的分段chunk表示數(shù)據(jù)傳輸完畢。

bool Http\Response->write(string $data)

參數(shù)$data表示要發(fā)送的數(shù)據(jù)內(nèi)容,最大長(zhǎng)度不得超過(guò)2MB,受buffer_output_size配置項(xiàng)控制。

Http\Response->sendfile

sendfile用于發(fā)送文件到瀏覽器

function Http\Response->sendfile(
  string $filename,
  int $offset = 0,
  int $length = 0
)
  • string $filename 表示要發(fā)送的文件名稱,文件不存在或沒(méi)有訪問(wèn)權(quán)限則會(huì)發(fā)送失敗。

  • int $offset 表示上傳文件的偏移量,可以指定從文件在中間部分開始傳輸數(shù)據(jù),用于斷點(diǎn)續(xù)傳,適用于Swoole1.9.11+。

  • int $length 表示發(fā)送數(shù)據(jù)的尺寸,默認(rèn)為整個(gè)文件的尺寸,適用于Swoole1.9.11+。

$response->header("Content-Type", "image/jpeg");

$filepath = $request->server["request_uri"];
$filename = __DIR__.$filepath;
$response->sendfile($filename);

由于Swoole底層無(wú)法推斷要發(fā)送文件的媒體類型MIME格式,因此需要應(yīng)用程序指定Content-Type。調(diào)用sendfile前不得使用write方法發(fā)送HTTP數(shù)據(jù)段Chunk,調(diào)用sendfile后Swoole底層會(huì)自動(dòng)執(zhí)行end方法,另外sendfile不支持gzip壓縮。

Http\Response->end

end方法用于發(fā)送HTTP響應(yīng)體,并結(jié)束請(qǐng)求處理。

function Http\Response->end(string $html);

end方法只能調(diào)用一次,如果需要分多次向客戶端發(fā)送數(shù)據(jù)下需使用write方法,send操作后將會(huì)向客戶端瀏覽器發(fā)送HTML內(nèi)容。如果客戶端開啟了KeepAlive連接會(huì)保持,服務(wù)器會(huì)等待下一次請(qǐng)求。如果沒(méi)有開啟KeepAlive服務(wù)器將會(huì)切斷連接。

Http\Response->detach

detach表示分離響應(yīng)對(duì)應(yīng),調(diào)用后$response對(duì)象銷毀時(shí)將不會(huì)自動(dòng)執(zhí)行end方法,一般detach會(huì)與Http\Response::create以及Server::send配合使用,適用于Swoole2.2.0+版本。

function Http\Response->detach():bool

detach方法操作后,若客戶端已經(jīng)完成響應(yīng)則會(huì)返回true,否則返回false

detach應(yīng)用于跨進(jìn)程響應(yīng)

在某些情況下需要在Task任務(wù)進(jìn)程中對(duì)客戶端發(fā)出響應(yīng),此時(shí)可以利用detach方法使$response對(duì)象獨(dú)立,如此一來(lái)在Task任務(wù)進(jìn)程中就可以重新構(gòu)建$response對(duì)象以發(fā)起HTTP請(qǐng)求響應(yīng)。

<?php
//創(chuàng)建HTTP服務(wù)器對(duì)象
$host = "0.0.0.0";
$port = 9501;
$server = new swoole_http_server($host, $port);

//設(shè)置服務(wù)器運(yùn)行參數(shù)
$configs = [];
$configs["worker_num"] = 1;//設(shè)置Worker工作進(jìn)程數(shù)量
$configs["task_worker_num"]  = 1;//設(shè)置Task任務(wù)進(jìn)程數(shù)量
$configs["daemonize"] = 0;//設(shè)置是否已后臺(tái)守護(hù)進(jìn)程運(yùn)行
$server->set($configs);

//注冊(cè)客戶端請(qǐng)求處理回調(diào)函數(shù)
$server->on("request", function(swoole_http_request $request, swoole_http_response $response) use($server){
    //分離響應(yīng)對(duì)象
    $response->detach();
    //在Task任務(wù)進(jìn)程中對(duì)客戶端發(fā)出響應(yīng)
    $fd = strval($response->fd);
    $server->task($fd);
});

//注冊(cè)異步任務(wù)處理回調(diào)函數(shù)
$server->on("task", function(swoole_http_server $server, $worker_id, $data){
    //創(chuàng)建響應(yīng)對(duì)象
    $response = swoole_http_response::create($data);
    //向客戶端發(fā)送響應(yīng)
    $html = "in task";
    $response->end($html);
});

//注冊(cè)Task異步任務(wù)執(zhí)行完畢回調(diào)函數(shù)
$server->on("finish", function(){
    echo "[finish] task".PHP_EOL;
});

//啟動(dòng)服務(wù)器
$server->start();

detach方法應(yīng)用于發(fā)送任意內(nèi)容

在某些特殊場(chǎng)景下,需要對(duì)客戶端發(fā)送特殊的響應(yīng)內(nèi)容,Http\Response對(duì)象自帶的end方法無(wú)法滿足需求,可以使用detach方法分離響應(yīng)對(duì)象,然后自行組包并使用Server::send方法發(fā)送數(shù)據(jù)。

<?php
//創(chuàng)建HTTP服務(wù)器對(duì)象
$host = "0.0.0.0";
$port = 9501;
$server = new swoole_http_server($host, $port);
//設(shè)置服務(wù)器運(yùn)行參數(shù)
$configs = [];
$configs["worker_num"] = 2;//設(shè)置Worker工作進(jìn)程數(shù)量
$configs["daemonize"] = 0;//設(shè)置是否已后臺(tái)守護(hù)進(jìn)程運(yùn)行
$server->set($configs);
//注冊(cè)監(jiān)聽(tīng)客戶端HTTP請(qǐng)求回調(diào)事件
$server->on("request", function(swoole_http_request $request, swoole_http_response $response) use($server){
    //分離響應(yīng)對(duì)象
    $response->detach();
    //自行組包并使用Server::send方法發(fā)送數(shù)據(jù)
    $fd = $response->fd;
    $message = "HTTP/1.1 200 OK\r\n";
    $message .= "Server: server\r\n";
    $message .= "\r\n";
    $message .= "Hello World\n";
    $server->send($fd, $message);
});
//啟動(dòng)服務(wù)器
$server->start();

Http\Response::create

create靜態(tài)方法用于構(gòu)造新的Http\Response響應(yīng)對(duì)象,使用前必須調(diào)用detach方法將舊有$response對(duì)象分離,否則 可能會(huì)造成同一個(gè)請(qǐng)求發(fā)送兩次響應(yīng)內(nèi)容。

function Http\Response::createE(int $fd) : Http\Response

create靜態(tài)方法的參數(shù)$fd表示需要綁定連接的文件描述符,調(diào)用Http\Response對(duì)象的end方法和write方法時(shí)會(huì)向此連接發(fā)送數(shù)據(jù)。如果調(diào)用成功則返回一個(gè)新的Http\Response對(duì)象,否則失敗返回false,適用于Swoole2.2.0+版本。


注冊(cè)事件回調(diào)函數(shù)

Http\Server注冊(cè)事件回調(diào)函數(shù)于Http\Server->on相同,不同之處在于HTTP\Server->on不接受onConnectonReceive回調(diào)設(shè)置,Http\Server->on會(huì)額外接受一種新的事務(wù)類型onRequest

onRequest 事件

onRequest事件適用于Swoole1.7.7+版本,當(dāng)服務(wù)器收到一個(gè)完整的HTTP請(qǐng)求后會(huì)調(diào)用onRequest函數(shù)。

$server->on("request", function(swoole_http_request $request, swoole_http_response $response) use($server){
  $html = "success";
  $response->end($html);
});

onRequest回調(diào)函數(shù)共有兩個(gè)參數(shù)

  • swoole_http_requst $request HTTP請(qǐng)求信息對(duì)象,包含了Header/GET/POST/Cookie等信息。

  • swoole_http_response $response HTTP響應(yīng)信息對(duì)象,支持Cookie/Header/Status等HTTP操作。

onRequest回調(diào)函數(shù)返回時(shí)會(huì)銷毀$request$response對(duì)象,如果未執(zhí)行$response->end()操作,Swoole底層會(huì)自動(dòng)執(zhí)行一次$response->end("")。

$request$response對(duì)象在傳遞給其它函數(shù)時(shí),是不需要添加&取地址的引用符號(hào)的,傳遞后引用計(jì)數(shù)會(huì)增加,當(dāng)onRequest退出時(shí)并不會(huì)被銷毀。

案例

$ vim http_server.php
<?php
$addr = "0.0.0.0";
$port = 9501;
$svr = new swoole_http_server($addr, $port);
$svr->on("request", function(swoole_http_request $rq, swoole_http_response $rp){
    //處理動(dòng)態(tài)請(qǐng)求
    $path_info = $rq->server["path_info"];
    $file = __DIR__.$path_info;
    echo "\nfile:{$file}";
    if(is_file($file) && file_exists($file)){
        $ext = pathinfo($path_info, PATHINFO_EXTENSION);
        echo "\next:{$ext}";
        if($ext == "php"){
            ob_start();
            include($file);
            $contents = ob_get_contents();
            ob_end_clean();
        }else{
            $contents = file_get_contents($file);
        }
        echo "\ncontents:{$contents}";
        $rp->end($contents);
    }else{
        $rp->status(404);
        $rp->end("404 not found");
    }
});
$svr->start();
# 創(chuàng)建靜態(tài)文件
$ vim index.html
index.html

# 測(cè)試靜態(tài)文件
$ curl 127.0.0.1:9501/index.html

# 觀察http_server輸出
file:/home/jc/projects/swoole/chat/index.html
ext:html
contents:index.html

# 測(cè)試動(dòng)態(tài)文件
$ vim index.php
<?php
echo "index.php";

#觀察http_server日志輸出
file:/home/jc/projects/swoole/chat/index.php
ext:php
contents:index.php

獲取動(dòng)態(tài)請(qǐng)求的參數(shù)

$ vim http_server.php
<?php
$addr = "0.0.0.0";
$port = 9501;
$svr = new swoole_http_server($addr, $port);
$svr->on("request", function(swoole_http_request $rq, swoole_http_response $rp){
    //獲取請(qǐng)求參數(shù)
    $params = $rq->get;
    echo "\nparams:".json_encode($params);
    //處理動(dòng)態(tài)請(qǐng)求
    $path_info = $rq->server["path_info"];
    $file = __DIR__.$path_info;
    echo "\nfile:{$file}";
    if(is_file($file) && file_exists($file)){
        $ext = pathinfo($path_info, PATHINFO_EXTENSION);
        echo "\next:{$ext}";
        if($ext == "php"){
            ob_start();
            include($file);
            $contents = ob_get_contents();
            ob_end_clean();
        }else{
            $contents = file_get_contents($file);
        }
        echo "\ncontents:{$contents}";
        $rp->end($contents);
    }else{
        $rp->status(404);
        $rp->end("404 not found");
    }
});
$svr->start();

測(cè)試帶參數(shù)的請(qǐng)求

$ curl 127.0.0.1:9501?k=v

觀察請(qǐng)求參數(shù)的輸出

params:{"k":"v"}
file:/home/jc/projects/swoole/chat/index.html
ext:html
contents:index.html

靜態(tài)文件處理

$ vim mimes.php
<?php
return [
    "jpg"=>"image/jpeg",
    "jpeg"=>"image/jpeg",
    "bmp"=>"image/bmp",
    "ico"=>"image/x-icon",
    "gif"=>"image/gif",
    "png"=>"image/png",
    "css"=>"text/css",
    "html"=>"text/html",
    "xml"=>"text/xml",
    "bin"=>"application/octet-stream",
    "js"=>"application/javascript",
    "tar"=>"application/x-tar",
    "ppt"=>"application/vnd.ms-powerpoint",
    "pdf"=>"application/pdf",
    "swf"=>"application/x-shockwave-flash",
    "zip"=>"application/x-zip-compressed"
];
$ vim http_server.php
<?php
//創(chuàng)建HTTP服務(wù)器
$addr = "0.0.0.0";
$port = 9501;
$srv = new swoole_http_server($addr, $port);
//設(shè)置HTTP服務(wù)器參數(shù)
$cfg = [];
$cfg["worker_num"] = 4;//設(shè)置工作進(jìn)程數(shù)量
$cfg["daemonize"] = 0;//守護(hù)進(jìn)程化,程序轉(zhuǎn)入后臺(tái)。
$srv->set($cfg);
//處理請(qǐng)求
$srv->on("request", function(swoole_http_request $rq, swoole_http_response $rp) use($srv){
    //獲取請(qǐng)求文件信息與文件后綴
    $path_info = $rq->server["path_info"];
    $ext = pathinfo($path_info, PATHINFO_EXTENSION);
    //文件是否存在
    $file = __DIR__.$path_info;
    if(!is_file($file) || !file_exists($file)){
        $rp->status(404);
        $rp->end("404 NOT FOUND");
    }
    //處理靜態(tài)請(qǐng)求
    if($ext != "php"){
        //設(shè)置響應(yīng)頭信息的內(nèi)容內(nèi)容
        $mimes = include("mimes.php");
        $rp->header("Content-Type", $mimes[$ext]);
        //獲取靜態(tài)文件內(nèi)容
        $contents = file_get_contents($file);
        //返回內(nèi)容
        $rp->end($contents);
    }
});
//啟動(dòng)服務(wù)
$srv->start();

發(fā)送請(qǐng)求,瀏覽器訪問(wèn)127.0.0.1:9501/test.jpeg,查看圖片。

面向?qū)ο?/strong>

$ vim http_server.php
<?php
class HttpServer
{
    public static function run($host, $port, $options=[])
    {
        $srv = new swoole_http_server($host, $port);
        if(!empty($options)){
            $srv->set($options);
        }
        $srv->on("request", function(swoole_http_request $rq, swoole_http_response $rp) use($srv){
            $rp->end("test");
            $srv->close($rq->fd);
        });
        $srv->start();
    }
}

HttpServer::run("127.0.0.1", 9501, ["worker_num"=>2, "daemonize"=>0]);

壓力測(cè)試

使用Apache Bench工具進(jìn)行壓力測(cè)試可以發(fā)現(xiàn),swoole_http_server遠(yuǎn)超過(guò)PHP-FPM、Golang自帶的HTTP服務(wù)器、Node.js自帶的HTTP服務(wù)器,性能接近Nginx的靜態(tài)文件處理。

Swoole的http server與PHP-FPM的性能對(duì)比

安裝Apache的壓測(cè)工作ab

$ sudo apt install apache2-util

使用100個(gè)客戶端跑1000次,平均每個(gè)客戶端10個(gè)請(qǐng)求。

$ ab -c 100 -n 1000 127.0.0.1:9501/index.php

Concurrency Level:      100
Time taken for tests:   0.480 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      156000 bytes
HTML transferred:       9000 bytes
Requests per second:    2084.98 [#/sec] (mean)
Time per request:       47.962 [ms] (mean)
Time per request:       0.480 [ms] (mean, across all concurrent requests)
Transfer rate:          317.63 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   3.0      0      12
Processing:     4   44  10.0     45      57
Waiting:        4   44  10.1     45      57
Total:         16   45   7.8     45      57

Percentage of the requests served within a certain time (ms)
  50%     45
  66%     49
  75%     51
  80%     52
  90%     54
  95%     55
  98%     55
  99%     56
 100%     57 (longest request)

觀察可以發(fā)現(xiàn)QPS可以達(dá)到 Requests per second: 2084.98 [#/sec] (mean)。

HTTP SERVER 配置選項(xiàng)

swoole_server::set()用于設(shè)置swoole_server運(yùn)行時(shí)的各項(xiàng)參數(shù)化。

$cfg = [];
// 處理請(qǐng)求的進(jìn)程數(shù)量
$cfg["worker_num"] = 4;
// 守護(hù)進(jìn)程化
$cfg["daemonize"] = 1;
// 設(shè)置工作進(jìn)程的最大任務(wù)數(shù)量
$cfg["max_request"] = 0;

$cfg["backlog"] = 128;
$cfg["max_request"] = 50;
$cfg["dispatch_mode"] = 1;
$srv->set($cfg);

配置HTTP SERVER參數(shù)后測(cè)試并發(fā)

$ vim http_server.php
<?php
//創(chuàng)建HTTP服務(wù)器
$addr = "0.0.0.0";
$port = 9501;
$srv = new swoole_http_server($addr, $port);
//設(shè)置HTTP服務(wù)器參數(shù)
$cfg = [];
$cfg["worker_num"] = 4;//設(shè)置工作進(jìn)程數(shù)量
$cfg["daemonize"] = 1;//守護(hù)進(jìn)程化,程序轉(zhuǎn)入后臺(tái)。
$srv->set($cfg);

$srv->on("request", function(swoole_http_request $rq, swoole_http_response $rp){
    //獲取請(qǐng)求參數(shù)
    $params = $rq->get;
    echo "\nparams:".json_encode($params);
    //處理動(dòng)態(tài)請(qǐng)求
    $path_info = $rq->server["path_info"];
    $file = __DIR__.$path_info;
    echo "\nfile:{$file}";
    if(is_file($file) && file_exists($file)){
        $ext = pathinfo($path_info, PATHINFO_EXTENSION);
        echo "\next:{$ext}";
        if($ext == "php"){
            ob_start();
            include($file);
            $contents = ob_get_contents();
            ob_end_clean();
        }else{
            $contents = file_get_contents($file);
        }
        echo "\ncontents:{$contents}";
        $rp->end($contents);
    }else{
        $rp->status(404);
        $rp->end("404 not found");
    }
});

//啟動(dòng)服務(wù)
$srv->start();

查看進(jìn)程

$ ps -ef|grep http_server.php
root     16224  1207  0 22:41 ?        00:00:00 php http_server.php
root     16225 16224  0 22:41 ?        00:00:00 php http_server.php
root     16227 16225  0 22:41 ?        00:00:00 php http_server.php
root     16228 16225  0 22:41 ?        00:00:00 php http_server.php
root     16229 16225  0 22:41 ?        00:00:00 php http_server.php
root     16230 16225  0 22:41 ?        00:00:00 php http_server.php
root     16233  2456  0 22:42 pts/0    00:00:00 grep --color=auto http_server.php

查看后臺(tái)守護(hù)進(jìn)程

$ ps axuf|grep http_server.php
root     16622  0.0  0.0  21536  1044 pts/0    S+   22:46   0:00  |   |           \_ grep --color=auto http_server.php
root     16224  0.0  0.3 269036  8104 ?        Ssl  22:41   0:00  \_ php http_server.php
root     16225  0.0  0.3 196756  8440 ?        S    22:41   0:00      \_ php http_server.php
root     16227  0.0  0.6 195212 14524 ?        S    22:41   0:00          \_ php http_server.php
root     16228  0.0  0.6 195212 14524 ?        S    22:41   0:00          \_ php http_server.php
root     16229  0.0  0.6 195212 14524 ?        S    22:41   0:00          \_ php http_server.php
root     16230  0.0  0.6 195212 14524 ?        S    22:41   0:00          \_ php http_server.php

$ ps auxf|grep http_server.php|wc -l
7

殺死后臺(tái)進(jìn)程

# 強(qiáng)殺后臺(tái)進(jìn)程
$ kill -9 $(ps aux|grep swoole|grep -v grep|awk '{print $2}')
$ kill -9 16224
$ kill -9 16225
$ kill -9 16227
$ kill -9 16228
$ kill -9 16229
$ kill -9 16230

# 重啟后臺(tái)進(jìn)程
$ kill -10 $(ps aux|grep http_server|grep -v grep|awk '{print $2}')

壓測(cè)

$ ab -c 100 -n 1000 127.0.0.1:9501/index.php
Server Software:        swoole-http-server
Server Hostname:        127.0.0.1
Server Port:            9501

Document Path:          /index.php
Document Length:        9 bytes

Concurrency Level:      100
Time taken for tests:   0.226 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      156000 bytes
HTML transferred:       9000 bytes
Requests per second:    4417.72 [#/sec] (mean)
Time per request:       22.636 [ms] (mean)
Time per request:       0.226 [ms] (mean, across all concurrent requests)
Transfer rate:          673.01 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   2.8      0      11
Processing:     4   21   7.2     20      49
Waiting:        1   21   7.2     20      49
Total:          5   22   7.6     20      56

Percentage of the requests served within a certain time (ms)
  50%     20
  66%     23
  75%     25
  80%     26
  90%     30
  95%     38
  98%     45
  99%     53
 100%     56 (longest request)

觀察可以發(fā)現(xiàn)QPC為Requests per second: 4417.72 [#/sec] (mean)。

性能優(yōu)化

使用swoole_http_server服務(wù)后,若發(fā)現(xiàn)服務(wù)的請(qǐng)求耗時(shí)監(jiān)控毛刺十分嚴(yán)重,接口耗時(shí)波動(dòng)較大的情況,可以觀察下服務(wù)的響應(yīng)包response的大小,若響應(yīng)包超過(guò)1~2M甚至更大,則可判斷是由于包太多而且很大導(dǎo)致服務(wù)響應(yīng)波動(dòng)較大。

為什么響應(yīng)包惠導(dǎo)致相應(yīng)的時(shí)間波動(dòng)呢?主要有兩個(gè)方面的影響,第一是響應(yīng)包太大導(dǎo)致Swoole之間進(jìn)程通信更加耗時(shí)并占用更多資源。第二是響應(yīng)包太大導(dǎo)致Swoole的Reactor線程發(fā)包更加耗時(shí)。

感謝各位的閱讀,以上就是“Swoole與HTTP的使用介紹”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)Swoole與HTTP的使用介紹這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI