2011年4月25日 星期一

Parallel universe

Why an event can happen many times concurrently?
Does parallel universe exist... ?

...
...
......






......









............

















...
















其實呢篇文同平行宇宙無關。純粹標題黨。

最近玩Facebook果隻癲佬王國,入面有樣技能可以每12個鐘Call一隻癲佬出黎,用5點MP,出完之後粒掣會灰左。12個鐘有排等,要諗下辦法Bypass佢。既然粒掣灰左,我就整到佢唔灰,再出多一次,佢又幾醒識 check 住你之前用過未,彈一句 "請求參數錯誤"。

我心諗呢度都幾難Bypass咁,之後無端端諗到N年前某遊戲既一個Bug,就係如果同時進行戰鬥換武器,有時會複製多把武器。
咁我就用個 Fiddler 係咁 replay 堆 requests,之後同一時間 release 晒佢。結果係Call左7隻癲佬,同埋唔知點解剩係用左5點MP。
後來隻Game有個活動,參加左會多6個item,一日最多參加一次。我又出同一招,結果我由23個item變左做115個。最奇怪係唔知點解 115-23 唔係6既倍數。


Why flooding will work like this?
其實係因為個 server 根本唔可能同時處理晒咁多個 request 。睇下下面個例子(php):

<?php
error_reporting(0);

$fr = fopen('request.txt', 'a');
fwrite($fr,date("Y-m-d H:i:s")."\r\n");
fclose($fr);


$fo = fopen('counter_outer.txt', 'r');
$co = intval(fgets($fo));
echo("Outer: ".$co);
fclose($fo);

$fo = fopen('counter_outer.txt', 'w');
fwrite($fo,++$co);
echo("->".$co."<br />");
fclose($fo);


$fb = fopen('counter_barrier.txt', 'r');
$cb = intval(fgets($fb));
echo("Barrier: ".$cb);
fclose($fb);

if($cb<10){

$fb = fopen('counter_barrier.txt', 'w');
fwrite($fb,++$cb);
echo("->".$cb."<br />");
fclose($fb);


$fi = fopen('counter_inner.txt', 'r');
$ci = intval(fgets($fi));
echo("Inner: ".$ci);
fclose($fi);

$fi = fopen('counter_inner.txt', 'w');
fwrite($fi,++$ci);
echo("->".$ci."<br />");
fclose($fi);
}
echo('<br />End');
?>


上面段野都係求奇寫,入面有3個計數器,outer 係數總共收到幾多 request,barrier 係數總共有幾多個 request 過到個 if statement, inner 係數總共有幾多個 request 響個 if statement 入面 run 到。

如果你拍實 F5,個走勢會係咁:


Outer: 0->1
Barrier: 0->1
Inner: 0->1
...
Outer: 9->10
Barrier: 9->10
Inner: 9->10

Outer: 10->11
Barrier: 10
...
Outer: 29->30
Barrier: 10

開返 counter_inner.txt 睇,個 inner 都係 10
好自然去到 10 應該會截停晒 if statement 入面堆野,outer 就自己繼續加。

但係如果我響 if($cb<10){ 上面加句 sleep(1); 叫佢訓一秒,情況就唔同晒:


Outer: 0->1
Barrier: 0->1
Inner: 0->1
...
Outer: 40->41
Barrier: 2->3
Inner: 40->41


好不幸地 Barrier 個 counter 係咁用返舊果個數,搞到 Inner 果度可以 Run 多好多次。

個 sleep 放響邊都會影響個結果,呢樣野你地自己試下。