久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      一起看看Swoole HTTP

      一起看看Swoole HTTP

      目標

      • 了解swoole的http_server的使用
      • 了解swoole的tcp服務開發(fā)
      • 實際項目中問題如粘包處理、代理熱更新、用戶驗證等。
      • swoole與現(xiàn)有框架結合

      風格

      • 偏基礎重代碼

      環(huán)境

      • PHP版本:
      • Swoole版本:https://github.com/swoole/swoole-src
      • zphp開發(fā)框架:https://github.com/shenzhe/zphp

      HTTP Server

      • 靜態(tài)文件處理
      • 動態(tài)請求與框架結合
      # 查看SWOOLE版本 $ php -r 'echo SWOOLE_VERSION;' 4.3.1

      推薦(免費):swoole

      基礎概念

      HTTP報文

      關于HTTP請求報文的組成結構

      一起看看Swoole HTTP

      HTTP請求報文結構

      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

      關于HTTP響應報文的組成結構

      一起看看Swoole HTTP

      HTTP響應報文結構

      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服務器

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

      因為Swoole是在CLI命令行中執(zhí)行的,在傳統(tǒng)的NGINX+FastCGI模式下很多rootshell是無法執(zhí)行的,而使用Swoole服務器就能很好的控制rsyncgit、svn等。

      使用Swoole的API,構建HTTP服務器需要4個步驟

      1. 創(chuàng)建Server對象
      2. 設置運行時參數(shù)
      3. 注冊事件回調函數(shù)
      4. 啟動服務器
      # 創(chuàng)建應用 $ mkdir test && cd test  # 創(chuàng)建并編輯服務器文件 $ vim server.php
      <?php  //創(chuàng)建HTTP服務器對象 $host = "0.0.0.0"; $port = 9501; $server = new swoole_http_server($host, $port); var_dump($server);  //設置服務器運行參數(shù) $configs = []; $configs["worker_num"] = 2;//設置Worker工作進程數(shù)量 $configs["daemonize"] = 0;//設置是否已后臺守護進程運行 $server->set($configs);  //注冊監(jiān)聽客戶端HTTP請求回調事件 $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);         //獲取收包時間         var_dump($clientinfo["last_time"]);     }      //響應客戶端HTTP請求     $response->write("success");//向客戶端寫入響應數(shù)據(jù)     $response->end();//瀏覽器中輸出結果 });  //啟動服務器 $server->start();
      # 使用PHP-CLI運行服務器腳本 $ php server.php  # 使用CURL向HTTP服務器發(fā)送請求測試 $ curl 127.0.0.1:9501

      使用注意

      • echo、var_dump、print_r的內(nèi)容是在服務器中輸出的
      • 瀏覽器中輸出需要使用$rp->end(string $contents),end()方法只能調用一次。
      • 如果需要多次先客戶端發(fā)送消息可使用$rp->write(string $content)方法
      • 完整的HTTP協(xié)議請求會被解析并封裝在swoole_http_request對象中
      • 所有的HTTP協(xié)議響應會通過swoole_http_response對象進行封裝并發(fā)送

      HTTP服務器的本質

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

      一起看看Swoole HTTP

      swoole_http_server

      HttpServer

      SwooleHTTPServer繼承自Server,是一個HTTP服務器實現(xiàn),支持同步與有異步兩種模式。無論是同步模式還是異步模式,HTTP服務器都可以維持大量的TCP客戶端連接,同步與異步僅僅提現(xiàn)在對請求的處理方式。

      • 同步模式

      同步模式等同于Nginx+PHP-FPM/Apache,需要設置大量Worker工作進程來完成并發(fā)請求處理,Worker工作進程可以使用同步阻塞IO,編程方式與普通的PHP的Web程序完全一致。與PHP-FPM/Apache不同的是,客戶端連接并不會獨占進程,服務器依然可以應對大量并發(fā)連接。

      • 異步模式

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

      查看HTTP服務器實例對象

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

      配置選項

      文件上傳upload_tmp_dir

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

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

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

      POST解析http_parse_post

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

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

      POST尺寸 package_max_length

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

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

      解析Cookiehttp_parse_cookie

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

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

      文件壓縮http_compression

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

      由于http-chunk不支持分段獨立壓縮,因此默認已強制關閉了壓縮功能。

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

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

      壓縮級別http_compression_level

      http_compression_level選項用于配置壓縮的級別,壓縮級別越高壓縮后體積越小,同時也會越占用CPU。

      $configs = []; $configs["http_compression_level"] = 1; $server->set($configs);

      靜態(tài)根目錄document_root

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

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

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

      $configs = []; $configs["document_root"] = "/app"; $server->set($configs);

      靜態(tài)處理 enable_static_handler

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

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

      靜態(tài)處理器路徑static_handler_locations

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

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

      當啟用static_handler_locations選項后,如果請求對應的文件不存在,將直接會返回404錯誤。

      $configs = []; $configs["static_handler_locations"] = ["/static", "/public/assets"]; $server->set($configs);

      設置代理

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

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

      1. 設置服務器運行時環(huán)境
      $ vim server.php
      $configs = []; $configs["enable_static_handler"] =  true; $configs["document_root"] = "/test"; $server->set($configs);
      1. 設置Nginx反向代理配置

      例如:設置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;         }     } }

      請求對象

      swoole_http_request請求對象保存了HTTP客戶端請求的相關信息,包括GET、POST、COOKIE、Header等,請求對象$request銷毀時會自動刪除上傳的臨時文件,不要使用&符號引用$request請求對象。

      var_dump($request);  object(SwooleHttpRequest)#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 }

      HttpRequest->$header

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

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

      HttpRequest->$server

      HTTP請求相關的服務器信息,相當于PHP的$_SERVER全局數(shù)組,包含了HTTP請求的方法、URL路徑、客戶端IP等信息。服務器信息為關聯(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"];

      請求路徑

      當Google的Chrome瀏覽器訪問服務器是會產(chǎn)生兩次請求,這是因為Chrome會自動請求一次favicon.ico文件,所以服務器會收到兩個HTTP請求,通過打印$request->server["request_uri"]可以查看到請求URL路徑。如果需要屏蔽掉對favicon.ico的請求,可采用以下方式。

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

      收包時間

      request_time請求時間是在Worker工作進程中設置的,在SWOOLE_PROCESS多進程模式下存在dispatch分發(fā)的過程,因此可能會與實際收包時間存在偏差,尤其當請求量超過服務器處理能力時,有可能滯后于實際收包時間。

      可通過Server->getClientInfo()方法獲取last_time以獲取 準確的收包時間。

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

      客戶端信息

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

      bool|array Server->getClientInfo(int $fd, int $extraData, bool $ignoreError = false)
      • int $fd 表示客戶端連接文件描述符
      • int $extraData 表示擴展信息是保留參數(shù)目前無任何效果
      • bool $ignoreError 表示是否忽略錯誤,若設置為true表示即使連接關閉也會返回連接信息。

      如果傳入的$fd客戶端連接文件描述符存在則返回一個數(shù)組,若不存在或已關閉則返回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) }

      HttpRequest->$get

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

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

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

      WARN swReactorThead_onReceive_http_request: http header is too long.

      HttpRequest->$post

      HTTP請求攜帶POST參數(shù),格式為鍵值對的關聯(lián)數(shù)組,POSTHeader加起來的尺寸不得超過package_max_length的設置,否則會認為是惡意請求,另外POST參數(shù)的個數(shù)不得超過128個。

      $post = $request->post;

      由于POST文件上傳時最大尺寸收到package_max_length配置項目的限制,默認為2MB,可以調用swoole_server->set傳入新值修改尺寸。

      由于Swoole底層是全內(nèi)存的,因此如果設置過大可能會導致大量并發(fā)請求,將服務器資源耗盡。

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

      當使用CURL發(fā)送POST請求時服務器端會超時

      CURL在發(fā)送較大的POST請求時會首先發(fā)送一個100-continue的請求,當收到服務器的回應才會發(fā)送實際的POST數(shù)據(jù)。然后swoole_http_server并不支持100-continue,因此會導致CURL請求超時。解決的辦法時關閉CURL的100-continue。

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

      HttpRequest->$cookie

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

      HttpRequest->$files

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

      $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表示瀏覽器上傳時傳入的文件名稱
      • type表示瀏覽器上傳時的MIME類型
      • tmp_name 表示瀏覽器上傳的臨時文件,文件名默認以/tmp/swoole.upfile開頭。
      • size表示上傳文件的尺寸

      Swoole1.9.10+版本支持is_uploaded_filemove_uploaded_file函數(shù)。當HTTP請求對象$request對象銷毀時,會自動刪除上傳的臨時文件。

      HttpRequest->rawContent()

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

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

      string HTTPRequest->rawContent();

      HttpRequest->getData()

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

      function swoole_http_request_getData() : string

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

      響應對象

      swoole_http_response響應對象是進程隔離的,不能跨越進程或對象。如果是當前進程中,想使用fd文件描述符保存response響應對象、存儲上下文,可使用PHP全局數(shù)組變量來保存。

      swoole_http_response響應對象,通過調用此對象的方法實現(xiàn)HTTP響應的發(fā)送,當響應對象銷毀時,如果沒有調用end發(fā)送HTTP響應,底層會自動執(zhí)行end方法。不要使用&符號引用$response對象。

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

      HTTP服務器Response響應對象,通過調過此對象的方法,實現(xiàn)HTTP響應發(fā)送。當Response對象銷毀時,如果未調用則直接調用end方法,不要使用&符號引用$response對象。

      HttpResponse->header

      function HttpResponse->header(   string $key,   string $value,   bool $ucworods = true )

      header方法用于設置HTTP響應的Header頭信息,如果設置失敗返回false,設置成功則無返回值。

      • string $key 表示HTTP頭的Key
      • string $value 表示HTTP頭的Value
      • bool $ucwords 表示是否需要對Key進行HTTP約定格式化,默認true會自動格式化。
      $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; };

      HttpResponse->cookie

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

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

      Cookie設置必須在end方法之前方才生效,Swoole底層自動會對$value進行urlencode編碼處理,同時允許設置多個相同的$key的Cookie。

      HttpResponse->status

      swoole_http_response->status(   int $http_status_code )

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

      • string $url表示跳轉的新地址會作為HTTP Header頭中的Location選項進行發(fā)送
      • int $http_code 表示狀態(tài)碼,默認為302臨時跳轉,傳入301表示永久跳轉。

      HttpResponse->redirect

      redirect方法適用于Swoole2.2.0+版本,用于發(fā)送HTTP跳轉,調用后會自動執(zhí)行end方法并發(fā)送結束響應。

      function HttpResponse->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();

      HttpResponse->write

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

      bool HttpResponse->write(string $data)

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

      HttpResponse->sendfile

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

      function HttpResponse->sendfile(   string $filename,   int $offset = 0,   int $length = 0 )
      • string $filename 表示要發(fā)送的文件名稱,文件不存在或沒有訪問權限則會發(fā)送失敗。
      • int $offset 表示上傳文件的偏移量,可以指定從文件在中間部分開始傳輸數(shù)據(jù),用于斷點續(xù)傳,適用于Swoole1.9.11+。
      • int $length 表示發(fā)送數(shù)據(jù)的尺寸,默認為整個文件的尺寸,適用于Swoole1.9.11+。
      $response->header("Content-Type", "image/jpeg");  $filepath = $request->server["request_uri"]; $filename = __DIR__.$filepath; $response->sendfile($filename);

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

      HttpResponse->end

      end方法用于發(fā)送HTTP響應體,并結束請求處理。

      function HttpResponse->end(string $html);

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

      HttpResponse->detach

      detach表示分離響應對應,調用后$response對象銷毀時將不會自動執(zhí)行end方法,一般detach會與HttpResponse::create以及Server::send配合使用,適用于Swoole2.2.0+版本。

      function HttpResponse->detach():bool

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

      detach應用于跨進程響應

      在某些情況下需要在Task任務進程中對客戶端發(fā)出響應,此時可以利用detach方法使$response對象獨立,如此一來在Task任務進程中就可以重新構建$response對象以發(fā)起HTTP請求響應。

      <?php //創(chuàng)建HTTP服務器對象 $host = "0.0.0.0"; $port = 9501; $server = new swoole_http_server($host, $port);  //設置服務器運行參數(shù) $configs = []; $configs["worker_num"] = 1;//設置Worker工作進程數(shù)量 $configs["task_worker_num"]  = 1;//設置Task任務進程數(shù)量 $configs["daemonize"] = 0;//設置是否已后臺守護進程運行 $server->set($configs);  //注冊客戶端請求處理回調函數(shù) $server->on("request", function(swoole_http_request $request, swoole_http_response $response) use($server){     //分離響應對象     $response->detach();     //在Task任務進程中對客戶端發(fā)出響應     $fd = strval($response->fd);     $server->task($fd); });  //注冊異步任務處理回調函數(shù) $server->on("task", function(swoole_http_server $server, $worker_id, $data){     //創(chuàng)建響應對象     $response = swoole_http_response::create($data);     //向客戶端發(fā)送響應     $html = "in task";     $response->end($html); });  //注冊Task異步任務執(zhí)行完畢回調函數(shù) $server->on("finish", function(){     echo "[finish] task".PHP_EOL; });  //啟動服務器 $server->start();

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

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

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

      HttpResponse::create

      create靜態(tài)方法用于構造新的HttpResponse響應對象,使用前必須調用detach方法將舊有$response對象分離,否則 可能會造成同一個請求發(fā)送兩次響應內(nèi)容。

      function HttpResponse::createE(int $fd) : HttpResponse

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


      注冊事件回調函數(shù)

      HttpServer注冊事件回調函數(shù)于HttpServer->on相同,不同之處在于HTTPServer->on不接受onConnectonReceive回調設置,HttpServer->on會額外接受一種新的事務類型onRequest。

      onRequest 事件

      onRequest事件適用于Swoole1.7.7+版本,當服務器收到一個完整的HTTP請求后會調用onRequest函數(shù)。

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

      onRequest回調函數(shù)共有兩個參數(shù)

      • swoole_http_requst $request HTTP請求信息對象,包含了Header/GET/POST/Cookie等信息。
      • swoole_http_response $response HTTP響應信息對象,支持Cookie/Header/Status等HTTP操作。

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

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

      案例

      $ 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){     //處理動態(tài)請求     $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  # 測試靜態(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  # 測試動態(tài)文件 $ vim index.php <?php echo "index.php";  #觀察http_server日志輸出 file:/home/jc/projects/swoole/chat/index.php ext:php contents:index.php

      獲取動態(tài)請求的參數(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){     //獲取請求參數(shù)     $params = $rq->get;     echo "nparams:".json_encode($params);     //處理動態(tài)請求     $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();

      測試帶參數(shù)的請求

      $ curl 127.0.0.1:9501?k=v

      觀察請求參數(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服務器 $addr = "0.0.0.0"; $port = 9501; $srv = new swoole_http_server($addr, $port); //設置HTTP服務器參數(shù) $cfg = []; $cfg["worker_num"] = 4;//設置工作進程數(shù)量 $cfg["daemonize"] = 0;//守護進程化,程序轉入后臺。 $srv->set($cfg); //處理請求 $srv->on("request", function(swoole_http_request $rq, swoole_http_response $rp) use($srv){     //獲取請求文件信息與文件后綴     $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)請求     if($ext != "php"){         //設置響應頭信息的內(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);     } }); //啟動服務 $srv->start();

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

      面向對象

      $ 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]);

      壓力測試

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

      Swoole的http server與PHP-FPM的性能對比

      安裝Apache的壓測工作ab

      $ sudo apt install apache2-util

      使用100個客戶端跑1000次,平均每個客戶端10個請求。

      $ 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可以達到 Requests per second: 2084.98 [#/sec] (mean)。

      HTTP SERVER 配置選項

      swoole_server::set()用于設置swoole_server運行時的各項參數(shù)化。

      $cfg = []; // 處理請求的進程數(shù)量 $cfg["worker_num"] = 4; // 守護進程化 $cfg["daemonize"] = 1; // 設置工作進程的最大任務數(shù)量 $cfg["max_request"] = 0;  $cfg["backlog"] = 128; $cfg["max_request"] = 50; $cfg["dispatch_mode"] = 1; $srv->set($cfg);

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

      $ vim http_server.php
      <?php //創(chuàng)建HTTP服務器 $addr = "0.0.0.0"; $port = 9501; $srv = new swoole_http_server($addr, $port); //設置HTTP服務器參數(shù) $cfg = []; $cfg["worker_num"] = 4;//設置工作進程數(shù)量 $cfg["daemonize"] = 1;//守護進程化,程序轉入后臺。 $srv->set($cfg);  $srv->on("request", function(swoole_http_request $rq, swoole_http_response $rp){     //獲取請求參數(shù)     $params = $rq->get;     echo "nparams:".json_encode($params);     //處理動態(tài)請求     $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");     } });  //啟動服務 $srv->start();

      查看進程

      $ 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

      查看后臺守護進程

      $ 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

      殺死后臺進程

      # 強殺后臺進程 $ 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  # 重啟后臺進程 $ kill -10 $(ps aux|grep http_server|grep -v grep|awk '{print $2}')

      壓測

      $ 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服務后,若發(fā)現(xiàn)服務的請求耗時監(jiān)控毛刺十分嚴重,接口耗時波動較大的情況,可以觀察下服務的響應包response的大小,若響應包超過1~2M甚至更大,則可判斷是由于包太多而且很大導致服務響應波動較大。

      為什么響應包惠導致相應的時間波動呢?主要有兩個方面的影響,第一是響應包太大導致Swoole之間進程通信更加耗時并占用

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號