PHP的fsockopen函式詳解

2021-07-30 22:51:15 字數 2816 閱讀 8133

先來看看手冊是如何定義fsockopen函式的。

fsockopen— 開啟乙個網路連線或者乙個unix套接字連線。

resource fsockopen ( string

$hostname [, int

$port = -1 [, int &$errno

[, string &$errstr [, float

$timeout = ini_get("default_socket_timeout") ]]]] )

使用fsockopen方法和使用curl方法的實質都是去模擬http協議,所以重點在於如果去構造http協議。

注意:要使用此函式的功能,需要在php.ini檔案中開啟allow_url_open

//開啟連線通道

$fp=fsockopen('www.cnblogs.com',80,$errno,$errstr,30);

if(!$fp)

set_time_limit(0);

//通道開啟,模擬http請求,http協議標準的換行是\r\n

//http模擬完成,傳送給伺服器

//接受伺服器的返回結果

$out='';

while(!feof($fp))

echo $out;

fclose($fp);

在開發過程中常常遇到這樣的需求,模擬瀏覽器訪問某介面,並獲取返回資料。我們比較常使用的方法是fsockopen與介面建立連線,然後發出指令,然後通過fgets接受返回值。

我們常常寫這樣的**:

while(!feof($shnd))
fgets會獲取檔案描述符$shnd的當前的4096(也可能是別的常數)個位元組,如果還沒有到4096個位元組遇到換行符了,則只返回換行符及換行符之前的內容。

許多文件教程裡也都是這麼講的,這段**許多情況下也能正常執行。我一步一步跟蹤php語句的耗時,發現前面若干次的fgets都很快,最耗時的是最後一次fgets,有時長達幾秒,有時長達十幾秒。

原來這是伺服器的keepalive功能造成的,apache有這麼乙個設定(nginx等其他web伺服器也都有):keepalive,如果這個設定置為on,則完成一次請求後,伺服器並 不會關閉tcp連線,而是保持連線等待瀏覽器下次發起其他請求時直接利用這個連線。但是當fgets獲取最後一段內容時沒有發現換行符,也沒有檔案結束標誌(feof()),所以fgets獲取完內容後仍繼續等待,希望遇到換行符或者其他內容以達到4096個字元。於是,就這樣伺服器和php耗上了,互相 等待。耗了一會後,伺服器先耗不起了,畢竟伺服器的連線數很寶貴,當連線若干秒沒有活動,就會關掉這個連線(apache通過keepalivetimeout這個選項進行設定,這個值通常為5-15)。伺服器關掉連線之後,php這邊的fgets這才失落得返回最後一批內容, 訪問介面過程結束。

清楚了慢的原因就知道了解決方案了:

伺服器返回的http頭中包含有內容長度這個屬性,當已接受的內容長度與之相等時,我們就可以斷定:介面內容已經獲取完畢,不必再等了。具體做法 是:每次獲取不超過剩餘總長度的內容(min(4096, $leftlength))。剩餘總長度為0時,跳出while(feof($***xx))的迴圈。

經過這樣的修改,php通過sock方式訪問介面速度慢的問題已經基本解決了,但還不夠完美,繼續速度優化的思路還在keepalive上。

大家都知道訪問介面的耗時相當一部分是浪費在建立連線上,如果我們需要頻繁呼叫介面的話,還有很大的優化餘地。既然伺服器保持了連線,那如果php 也把連線儲存下來那是不是就不用建立連線了?答案是肯定的:第一次訪問介面時使用pfsockopenpfsockopenfsockopen唯一的 區別就是它建立的是長連線)函式建立與伺服器的連線,在訪問完成後不關掉(fclose)連線,以後的訪問就直接使用這個連線。具體到**裡就是:先判斷 有沒有連線,如果有,繼續用,如果沒有,建立pfsockopen連線。

另外,如果介面返回內容比較短(比如:小於50字元)的話,還有優化的餘地,那就是在http請求頭的accept-encoding中去掉gzip。它的作用是告訴伺服器,我(瀏覽器)可以接受壓縮過的內容,如果伺服器也支援gzip就壓縮後再返回,瀏覽器得到內容後解壓縮再顯示。但是如果 內容太短的話,壓縮後體積反而會增加,再加上壓縮、解壓縮的時間,就更加得不償失了。

經過以上幾步,訪問介面速度應該與瀏覽器一樣,理論上還會稍微快一點點。

PHP函式 fsockopen簡介

開啟網路的 socket 鏈結。語法 resuce fsockopen string hostname,int port,int errno string errstr int timeout 返回值 資源 函式種類 網路系統 內容說明 目前這個函式提供兩個 socket 資料流介面,分別為 int...

php使用fsockopen實現非同步

php使用fsockopen實現非同步 parem post data post 請求引數 parem exetime 非同步任務執行時間 單位秒 parem debug 是否開啟除錯模式 function request by fsockopen url,post data array exeti...

php定時計畫任務與fsockopen持續程序例項

web伺服器執行乙個php指令碼,有時耗時很長才能返回執行結果,後面的指令碼需要等待很長一段時間才能繼續執行。如果想實現只簡單觸發耗時指令碼的執行而不等待執行結果就直接執行下一步操作,可以通過fscokopen函式來實現。php支援socket程式設計,fscokopen函式返回乙個到遠端主機連線的...