2013-02-27 132 views
1

我有一個功能,通過捲曲發送HTTP請求到www.server.comPHP防止同時執行功能(通過節流PHP限制)

我的任務是確保www.server.com獲得不超過每2秒一次請求。

可能的解決方案:

創建一個功能checktime(),將當前的通話時間存儲在數據庫中,並在每個下次調用與數據庫檢查並進行系統停頓2秒:

$oldTime = $this->getTimeFromDatabase(); 
if ($oldTime < (time() - 2)) { // if its been 2 seconds 
    $this->setNewTimeInDatabase(); 
    return true; 
} else { 
    sleep(2); 
    return false; 
} 

問題/問題:

可以說,最後一次請求www.server.com是1361951000.然後10個其他用戶嘗試請求1361951001(1秒鐘後)。 checktime()函數將被調用。

由於它只有1秒,函數將返回false。所有10個用戶將等待2秒鐘。這是否意味着在1361951003上有10個請求會同時發送?是否有可能在數據庫中不會更改最後一次請求的時間,因爲在checktime()中錯過了$ this-> setNewTimeInDatabase()的調用?

謝謝!

UPDATE:

我剛纔被告知,使用循環可能解決這個問題:

for($i=0;$i<300;$i++) 
{ 
    $oldTime = $this->getTimeFromDatabase(); 
    if ($oldTime < (time() - 2)) { // if its been 2 seconds 
    $this->setNewTimeInDatabase(); 
    return true; 
    } else { 
    sleep(2); 
    return false; 
    } 
} 

但我實在不明白它的邏輯。

+0

對'www.server。'進行檢查會更好。com'? – Zaffy 2013-02-27 20:11:00

+0

@Zaffy我無法訪問'www.server.com' – rinchik 2013-02-27 20:11:39

+0

另一種方法是創建一個靜態變量,它像一個que一樣工作,然後在2秒鐘後,來自que的下一個項目被髮送到服務器。 COM。這必須是一個靜態變量,因此它可以在你的類的所有實例中共享。 – Mike 2013-02-27 20:12:35

回答

1

我相信你需要一些執行semaphore。數據庫可以工作,只要你能保證只有一個線程可以寫入數據庫然後發出請求。

例如,您可能會使用對數據庫的更新請求,然後檢查更新的行(以檢查更新是否真的發生)。如果更新成功,您可以假設您獲得了互斥鎖,然後發出請求(假定時間是正確的)。這樣的事情:

$oldTime = $this->getTimeFromDatabase(); 
if ($oldTime < (time() - 2) && $this->getLock()) { // if its been 2 seconds 
    $this->setNewTimeInDatabase(); 
    $this->releaseLock(); 
    return true; 
} else { 
    sleep(2); 
    return false; 
} 

function getLock() 
{ 
    return $mysqli->query('UPDATE locktable set locked = 1 WHERE locked = 0'); 
} 

function releaseLock() 
{ 
    $mysqli->query('UPDATE locktable set locked = 0'); 
} 

我不確定mysql函數,但我相信這是可以得到的一般想法。

+0

嗯......如果我只是檢查數據庫更新是否發生,該怎麼辦? 'if($ oldTime <(time() - 2)&& $ this-> setNewTimeInDatabase())' – rinchik 2013-02-27 20:57:27

+0

呃,實際上我必須改變我原來的答案,以便使它更加明確,但原則是站得住腳的。使用數據庫作爲鎖定機制的想法是確保原子性(我的意思是,確保只有一個線程可以在任何時候執行操作)。如果你沒有實現這樣的機制,你不能確定只有一個人需要設置NewTime。 – Muc 2013-03-15 14:40:32

+0

謝謝!我實現了表鎖:) – rinchik 2013-03-15 15:02:47

1

小心使用數據庫。例如,MySQL並不總是與它的會話同步,因此,爲了鎖定目的,依賴它是不安全的。

您可以通過方法flock使用文件鎖,您可以在其中保存訪問時間。然後,您可以確保鎖定該文件,以免兩個或更多進程同時訪問它。

它可能會去是這樣的:

$filepath = "lockfile_for_source"; 
touch($filepath); 
$fp = fopen("lockfile_for_resource", "r") or die("Could not open file."); 

while(true){ 
    while(!flock($fp, LOCK_EX)){ 
    sleep(0.25); //wait to get file-lock. 
    } 

    $time = file_get_contents($filepath); 
    $diff = time() - $time; 
    if ($diff >= 2){ 
    break; 
    }else{ 
    flock($fp, LOCK_UN); 
    } 
} 

//Following code would never be executed simultaneously by two scripts. 
//You should access and use your resource here. 

fwrite($fp, time()); 
fflush($fp); 
flock($fp, LOCK_UN); //remove lock on file. 
fclose($fp); 

請注意,我沒有測試的代碼。

+0

這也可以工作,但是如果您需要從幾個不同的服務器執行查詢,本地文件將無法執行。 – Muc 2013-02-27 20:36:05

+1

在這種情況下,分佈式鎖將解決問題。這需要建立一個像[flaco-lock-service](https://code.google.com/p/flaco-lock-service/) 這樣的系統,或者可以安裝一個共享在服務器之間共享,然後使用文件鎖定。 – kaspernj 2013-02-27 20:54:54

+0

我不能設置任何系統或安裝任何東西。我需要在幾行代碼中解決它:) – rinchik 2013-02-27 20:59:09