shm_put_var 沒有防止競爭條件的保護機制。如果兩個腳本同時插入相同的鍵,PHP 可能會發生區段錯誤。
(PHP 4, PHP 5, PHP 7, PHP 8)
shm_put_var — 在共享記憶體中插入或更新變數
shm_put_var() 會插入或更新給定 key
的 value
值。
如果 shm
不是有效的 SysV 共享記憶體索引,或者沒有足夠的共享記憶體剩餘空間來完成您的請求,則會發出警告 (E_WARNING
等級)。
shm
從 shm_attach() 獲取的共享記憶體區段。
key
變數鍵值。
value
變數。所有 serialize() 支援的變數類型 都可以使用:通常這表示除了資源和一些無法序列化的內部物件之外的所有類型。
很遺憾,Troy 是對的
以下腳本將返回
resource(5) of type (stream) (資源(5),類型為(串流))
int(0) (整數(0))
<?php
define("FOPEN_RESOURCE", 1);
define("FOPEN_FILEPATH", "/path/to/file");
$fopen_resource = fopen(FOPEN_FILEPATH, "w");
var_dump($fopen_resource);
$shm_id = shm_attach(1);
if ($shm_id === false)
{
echo "Fail to attach shared memory.\n";
}
if (!shm_put_var($shm_id, FOPEN_RESOURCE, $fopen_resource))
{
echo "Failed to put var 1 in shared memory $shm_id.\n";
}
$sm_fopen_resource = shm_get_var($shm_id, FOPEN_RESOURCE);
if ($sm_fopen_resource === false)
{
echo "Failed to retreive fopen_resource from Shared memory\r\n";
}
var_dump($sm_fopen_resource);
if($shm_id) shm_remove($shm_id);
if($fopen_resource) fclose($fopen_resource);
?>
它會支援像 pfsockopen() 指標這樣的資源識別符號嗎?
主要的問題是,當我們以 Apache 模組的方式運行 PHP 時,我們永遠不知道下一個請求會綁定到哪個處理程序,這使得我們不可能擁有真正的持久性 Socket 連線,除非我們可以儲存它的指標,或者直接使用像 fopen() 之類的函式打開 Socket inode 並再次取得相同的資源指標。
我以為我可以使用 shm,但似乎 shm 不允許儲存資源指標... 令人難過... :(
引言:「它會支援像 pfsockopen() 指標這樣的資源識別符號嗎?... 我們以 Apache 模組的方式運行 PHP ... 沒有辦法擁有真正的持久性 Socket」
抱歉,但這對我來說沒有道理... Socket 仍然是持久性的,如果你想繼續使用它,只需使用相同的主機和埠呼叫 pfsockopen() - 你就會得到相同的 Socket。不需要傳遞實際的資源變數。
如果每個 Socket 都有非常特殊和獨特的東西,你可以執行以下操作 - 這應該適用於任何持久性資源
要區分或取得特定資源,只需序列化/儲存每個資源唯一 ID 的索引,以及使該資源獨一無二的特定資訊。
您可以像這樣取得整數值的唯一資源識別碼:
<?php
$rid = str_replace("Resource id #", "", print_r($fp, true));
// $rid = 2
?>
由於 pfsockopen() 使用主機名稱和連接埠作為恢復持續連線的唯一鍵,您可以新增 DNS 萬用字元,或在 /etc/hosts(或 Windows 對應檔案)中新增一些手動項目,如下所示:
resource-0.host.com 192.168.100.1
resource-1.host.com 192.168.100.1
resource-2.host.com 192.168.100.1
resource-3.host.com 192.168.100.1
然後,查閱您序列化的資源列表後,您可以使用其資源 ID 連線到特定資源。
例如: $pf = pfsockopen("resource-$rid.host.com", $port, $timeout);
新的資源將與原始資源完全相同。
對於基於檔案的串流資源,您可以使用符號連結執行類似的操作,或使用下一個方法...
對於基於 URL 或其他具有「路徑」的資源(我不知道是否有涉及此類操作的持續性函式),您可以使用路徑中的額外資訊來區分它們。例如:
http://host.com/resource-4/../script.php
http://resource4@host.com/script.php
/tmp/././././file.txt
在第一個範例中,額外的「resource-4」將被網路伺服器忽略。
在第二個範例中,多餘的使用者名稱將被網路伺服器忽略。(對於 mysql_pconnect,可以使用多個使用者名稱執行類似的操作)。
在第三個範例中,四個連續出現的「無效」字串 "./" 表示資源 #4。
如果這還不夠,您可以利用 PHP 共享記憶體資源與其 .c 對應資源互通的事實。這允許您編寫一個輕量級的 .c 應用程式來處理繁重的工作。
或者,您可以嘗試使用持續性串流和上述方法重新連線到您自己的網路伺服器,以達到最終結果。我想不出在哪種情況下需要如此極端的做法,但我相信這並非不可能。
我個人使用一個 117 MB 的二進位資料庫,它儲存在共享記憶體中,可以從命令列(使用編譯的 .c 應用程式)和網路(透過 PHP 和 ftok()/shmop_open()/shmop_read())存取。
是的,使用共享記憶體可以維持真正的資源持久性。PHP 中的所有變數都以 zval 的形式儲存在通用雜湊表中,包括資源識別碼。只要整個 PHP 程序沒有關閉,就有雜湊表可以比請求存活更久。您只需要將識別碼儲存在這樣的雜湊表中,並找到一種方法來追蹤它們,就可以收到原始資源。
我不知道為什麼 PHP 不提供設定/取得持續性資源的方法,但这可能是因為它有許多類型的 SAPI 可用,而且並非所有 SAPI 都*可以*做到這一點,包括仍然遠未過時的 CGI。
另一個問題是,在使用者空間擁有這樣的存取權限勢必會造成多個 PHP 程序嘗試存取相同資源的狀況。從這個角度來看,如果 PHP 沒有更好的同步機制,就沒有真正安全的方法來使用這些 getter/setter。
盡可能減少使用 variable_key。對於大型數據陣列,建議將陣列設為多維並儲存在一個 variable_key 下,而不是將 variable_key 用作索引。當需要重複從陣列末端擷取數據且更新頻率較低時,這種做法的優勢尤其明顯。