ก๊วนซอฟท์แวร์ </softganz> SoftGang (Gang Software)

Web &amp; Software Developer Gang.

Shoutcast radio status

by Little Bear @25 ส.ค. 52 12:43 ( IP : 61...85 ) | Tags : Shoutcast , PHP

ปัญหาเกิดมาจาก script สำหรับตรวจสอบสถานะและแสดงชื่อเพลงที่กำลังเปิดอยู่นั้นกิน CPU time เยอะมาก และ script นั้นยังถูกกำหนดให้ refresh ทุก 30 วินาที เมื่อมีคนเปิดฟังวิทยุพร้อมกับดูสถานะเป็นจำนวนมาก จะทำให้เกิดปัญหากับ CPU load

เลยศึกษา script นั้นดูและเปลี่ยนวิธีการเพื่อไม่ให้เกิด CPU load

แนวทางการทำงานของ script เดิมที่เป็นอยู่

  1. จะดึงข้อมูลของ Shoutcast จาก host ด้วย fsocket method GET จำนวน 2 ครั้ง คือ ชื่อเพลง กับจำนวนคนฟัง โดยกำหนด timeout ไว้ที่ 6 วินาที
  2. ตัดข้อความที่ไม่ต้องการออกและแยกแยะเอาข้อความที่ต้องการออกมา
  3. แสดงผลในหน้าเว็บโดยให้ refresh ทุก ๆ 30 วินาที

ปัญหาที่เกิดขึ้นคือ

  1. การดึงข้อมูลผ่าน fsocket แต่ละครั้งใช้เวลาพอสมควรเนื่องจาก script อยู่คนละที่กับ Shoutcast server
  2. เกิด CPU load ในกระบวนการไหนไม่แน่ใจ
  3. จำนวน request ที่เยอะมากเกิดจาก จำนวนคนฟังหรือหน้าเว็บที่เปิดดูสถานะ x 2 คร้ง/นาที เช่น 150x2=300 ครั้ง/นาที = 5 ครั้ง/วินาที ทำ script ทำงานไม่ทัน

แนวทางใหม่ที่คิดคือ

แทนที่จะให้ทุกคน request แล้วต้องอ่านข้อมูลทุกครั้ง ก็ให้ script ทำงานอัตโนมัติทุก ๆ 30 วินาที ไปดึงข้อมูลจาก Shoutcast แล้วบันทึกเก็บไว้ในไฟล์ แล้วให้ทุกคนอ่านจากไฟล์นี้แทน

ดูตัวอย่าง script ได้จากด้านในนะครับ

ผมเลยปรับแก้โปรแกรมเป็นตามนี้

&lt;?php
/**
 * Radio configuration
 *
 */
//include ("shoutcast_stat_config.php");
$radiohost= 'xxx.xxx.xxx.xxx'; // server ip address
$radioport= '8006'; // server port
$radioofflinemsg='Offline';
$radiopassword='password here'; // password
$output_file='/{path/to/public_html}/radiostatus.html';

$ret='';
$timeout='6';
$listenlink='http://'.$radiohost.':'.$radioport.'/listen.pls';
$radio= @fsockopen($radiohost, $radioport, &$errno, &$errstr, $timeout);
if (!$radio) {
    $success='2';
    $ret.=$radioofflinemsg; // Radio is offline, so display message
    die();
}
//Connect to the server
if ($success!='2') { //If Connection
    fputs($radio,"Get /7.html HTTP/1.0\r\nUser-Agent: XML Getter (Mozilla Compatible)\r\n\r\n"); //Get 7.HTML
    while (!feof($radio)) {
        $page.=fgets($radio, 1000);
    }
    $page=ereg_replace('.*&lt;body&gt;', '', $page);
    $page=ereg_replace('&lt;/body&gt;.*', ',', $page);
    $numbers=explode(',',$page);
    $currentlisteners=$numbers[0];
    $connected=$numbers[1];
    //Open Connection
    $fp=fsockopen($radiohost, $radioport, &$errno, &$errstr, 3);
    if (!$fp) { //If Connection
        $success2='2';
        $ret.='The Radio Server Is Currently Offline';
    }
    if ($success2!='2') { //If Connected
        fputs($fp,"Get /admin.cgi?pass=$radiopassword&mode=viewxml HTTP/1.0\r\nUser-Agent: XML Getter (Mozilla Compatible)\r\n\r\n");
        while(!feof($fp)) {
            $page.= fgets($fp, 1000);
        }
        $security=explode(',',$page);
        $security=explode('401',$security[7]);
        $u='0';
        while ($security[$u]!='') {
            if ($security[1]!='') {
                $ret.='Incorrect Server Password';
                die;
            }
            $u++;
        }
    //Array
    $loop=array('AVERAGETIME', 'SERVERGENRE', 'SERVERURL', 'SERVERTITLE', 'SONGTITLE', 'SONGURL', 'IRC', 'ICQ', 'AIM', 'WEBHITS', 'STREAMHITS', 'INDEX','LISTEN', 'PALM7', 'LOGIN', 'LOGINFAIL', 'PLAYED', 'COOKIE', 'ADMIN', 'UPDINFO', 'KICKSRC', 'KICKDST', 'UNBANDST', 'BANDST', 'VIEWBAN', 'UNRIPDST', 'VIEWRIP', 'VIEWXML', 'VIEWLOG', 'INVALID'); //Define All The Variables To Get (Delete Any Ones You Don't Want)
    $y='0';
    while ($loop[$y]!='') {
        $pageed=ereg_replace(".*&lt;$loop[$y]&gt;", "", $page); //Extract Data
        $phpname=strtolower($loop[$y]);
        $$phpname=ereg_replace("&lt;/$loop[$y]&gt;.*", "", $pageed); //Finish Extracting Data
        if($loop[$y]==SERVERGENRE || $loop[$y]==SERVERTITLE || $loop[$y]==SONGTITLE)
            $$phpname=urldecode($$phpname);
            $phpname = $phpname;
            $y++;
        }
    }
    $wordconnected=$connected=='1'?'yes':'no';
    $peaklisteners=$numbers[2];
    $maxlisteners=$numbers[3];
    $reportedlisteners=$numbers[4];
    $song=$numbers[6];
    $bitrate=$numbers[5];
    $site=explode(' ', $servertitle);
    $title=explode('DJ',$servertitle);
    if ($wordconnected=='no' && $connected=='0') {
        $ret.=$radioofflinemsg;
    } else {
        $ret.='&lt;div align="center"&gt;'.$reportedlisteners.'/'.$maxlisteners.' Listeners&lt;br /&gt;Song: '.$numbers[6].'&lt;a href="'.$listenlink.'"&gt;&lt;/a&gt;&lt;/div&gt;';
        //Close Connection
        fclose($radio);
    }
}
$body='&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-EN"&gt;
&lt;head profile="http://gmpg.org/xfn/11"&gt;
&lt;title&gt;Shoutcast Stat&lt;/title&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=tis-620" /&gt;
&lt;meta http-equiv="refresh" content="30" /&gt;
&lt;meta http-equiv="cache-control" content="no-cache" /&gt;
&lt;meta http-equiv="pragma" content="no-cache" /&gt;
&lt;/head&gt;
&lt;body style="background-color:#FB803F;"&gt;
'.$ret.'
&lt;/body&gt;
&lt;/html&gt;';
$fh=fopen($output_file,'w');
fwrite($fh, $body);
fclose($fh);
?&gt;

ผลลัพที่ได้มาจะอยู่ในไฟล์ radiostatus.html ซึ่งต้องบันทึกไว้ในโฟลเดอร์ที่สามารถเปิดผ่าน url ได้

ขั้นตอนต่อไป คือ ทำให้ script นี้ทำงาน auto ทุก ๆ 30 วินาที จึงใช้ crontab เข้ามาช่วย ปัญหาคือ crontab มีหน่วยเล็กที่สุดในการทำงานคือ นาที ข้อมูลจาก อาจารย์กู ได้ Slicehost Forum - Is It Possible To Run A Cron Task Every 30 Seconds มาว่า ให้ทำ script ตัวหนึ่งที่จะเรียก script ที่ต้องการ run แล้วให้ sleep 30 วินาที แล้วเรียก script ที่ต้องการ run อีกครั้ง แล้วกำหนดให้ crontab ทำงาน script ทุก 1 นาที

ก็เลยสร้างไฟล์ radiofetch.sh ให้มีคำสั่งดังนี้

#!/bin/sh
/usr/local/bin/php /{path/to/public_html}/radiofetch.php &
sleep 30
/usr/local/bin/php /{path/to/public_html}/radiofetch.php &

แล้วสร้าง crontab

crontab -e

ป้อนค่า

* * * * * /{path/to/script}/radiofetch.sh

ผลลัพท์ที่ได้จะอยู่ที่ไฟล์ radiostatus.html คราวนี้ก็ให้เรียกไฟล์ radiostatus.html ไปแสดงผลแทน

!!!! โย่ CPU load หายเกลี้ยงเลย.....

หมายเหตุ - script นี้ผมไม่ได้เขียนเอง แต่เป็น script ที่มีแจกกันอยู่ในอินเตอร์เน็ต แต่ไม่ไม่รู้ว่าใครเขียนเพราะ script ที่ผมได้มานั้นไม่มีส่วนหมายเหตุของชื่อคนเขียน หากใครมีข้อมูลเกี่ยวกับผู้เขียน ช่วยบอกด้วยนะครับ จะได้ใส่ไว้ในเครดิตและอ้างอิงกลับให้

Comment #1
Mike (Not Member)
Posted @26 พ.ย. 52 14:06 ip : 195...73

I won't pretend to understand how, but it really works! thanks for sharing! useful and much appreciated. used to read a lot about it, downloaded great articles by torrent search engine  it's hard to decide what's really worth my attention. your site is very informative. thanks, you saved so much time