2

我有一个通过 CURL 向 www.server.com 发送 HTTP 请求的函数

我的任务是确保 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个请求?并且是否有可能由于 $this->setNewTimeInDatabase() 中未接来电,数据库中最后一次请求的时间不会改变checktime()

谢谢!

更新:

我刚刚被告知使用循环可能会解决问题:

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;
   }
}

但我真的没有看到其中的逻辑。

4

2 回答 2

2

我相信你需要一些信号量的实现。只要您可以保证只有一个线程可以写入数据库然后发出请求,数据库就可以工作。

例如,您可以对数据库使用更新请求,然后检查更新的行(以检查更新是否实际发生)。如果更新成功,您可以假设您获得了互斥锁,然后发出请求(假设时间合适)。像这样的东西:

$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 的功能,但我相信可以大致了解一下。

于 2013-02-27T20:34:36.070 回答
1

小心使用数据库。例如 MySQL 并不总是 100% 与它的会话同步,因此依赖它来锁定是不安全的。

您可以通过方法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);

请注意,我没有测试过代码。

于 2013-02-27T20:26:27.700 回答