Shoutcast radio status
ปัญหาเกิดมาจาก script สำหรับตรวจสอบสถานะและแสดงชื่อเพลงที่กำลังเปิดอยู่นั้นกิน CPU time เยอะมาก และ script นั้นยังถูกกำหนดให้ refresh ทุก 30 วินาที เมื่อมีคนเปิดฟังวิทยุพร้อมกับดูสถานะเป็นจำนวนมาก จะทำให้เกิดปัญหากับ CPU load
เลยศึกษา script นั้นดูและเปลี่ยนวิธีการเพื่อไม่ให้เกิด CPU load
แนวทางการทำงานของ script เดิมที่เป็นอยู่
- จะดึงข้อมูลของ Shoutcast จาก host ด้วย fsocket method GET จำนวน 2 ครั้ง คือ ชื่อเพลง กับจำนวนคนฟัง โดยกำหนด timeout ไว้ที่ 6 วินาที
- ตัดข้อความที่ไม่ต้องการออกและแยกแยะเอาข้อความที่ต้องการออกมา
- แสดงผลในหน้าเว็บโดยให้ refresh ทุก ๆ 30 วินาที
ปัญหาที่เกิดขึ้นคือ
- การดึงข้อมูลผ่าน fsocket แต่ละครั้งใช้เวลาพอสมควรเนื่องจาก script อยู่คนละที่กับ Shoutcast server
- เกิด CPU load ในกระบวนการไหนไม่แน่ใจ
- จำนวน request ที่เยอะมากเกิดจาก จำนวนคนฟังหรือหน้าเว็บที่เปิดดูสถานะ x 2 คร้ง/นาที เช่น 150x2=300 ครั้ง/นาที = 5 ครั้ง/วินาที ทำ script ทำงานไม่ทัน
แนวทางใหม่ที่คิดคือ
แทนที่จะให้ทุกคน request แล้วต้องอ่านข้อมูลทุกครั้ง ก็ให้ script ทำงานอัตโนมัติทุก ๆ 30 วินาที ไปดึงข้อมูลจาก Shoutcast แล้วบันทึกเก็บไว้ในไฟล์ แล้วให้ทุกคนอ่านจากไฟล์นี้แทน
ดูตัวอย่าง script ได้จากด้านในนะครับ
ผมเลยปรับแก้โปรแกรมเป็นตามนี้
<?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('.*<body>', '', $page); $page=ereg_replace('</body>.*', ',', $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(".*<$loop[$y]>", "", $page); //Extract Data $phpname=strtolower($loop[$y]); $$phpname=ereg_replace("</$loop[$y]>.*", "", $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.='<div align="center">'.$reportedlisteners.'/'.$maxlisteners.' Listeners<br />Song: '.$numbers[6].'<a href="'.$listenlink.'"></a></div>'; //Close Connection fclose($radio); } } $body='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-EN"> <head profile="http://gmpg.org/xfn/11"> <title>Shoutcast Stat</title> <meta http-equiv="Content-Type" content="text/html; charset=tis-620" /> <meta http-equiv="refresh" content="30" /> <meta http-equiv="cache-control" content="no-cache" /> <meta http-equiv="pragma" content="no-cache" /> </head> <body style="background-color:#FB803F;"> '.$ret.' </body> </html>'; $fh=fopen($output_file,'w'); fwrite($fh, $body); fclose($fh); ?>
ผลลัพที่ได้มาจะอยู่ในไฟล์ 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 ที่ผมได้มานั้นไม่มีส่วนหมายเหตุของชื่อคนเขียน หากใครมีข้อมูลเกี่ยวกับผู้เขียน ช่วยบอกด้วยนะครับ จะได้ใส่ไว้ในเครดิตและอ้างอิงกลับให้
Relate topics
- nginx - ถึงเวลาซะที
- PHP PDO using
- การเก็บ JSON ใน MySQL ด้วย PHP
- macOS 12 Monterey: Web Server Setup/Apache/MariaDB/PHP Multiple Versions
- Ubuntu Server Installation
- Bug : isset($body['location']) ดันเป็นจริงเมื่อ $body ไม่ใช่ array
- MVC - แนวคิดเกี่ยวกับ MVC
- FTP chmod
- Hash & Salt
- Regular Expression - ยังไง ยังไง ก็ใช้ไม่ถูกสักที
- PHP : How to show Adsense on web
- PHP : Send SMS by smsgateway.com
- Directadmin PHP path
- Application Programming Interface (API)
- IP Camera snapshot
- Enable Exif
- Make Ubuntu to be a web server (LAMP)
- SELECT - OnChange
- Class fpdf กับภาษาไทย
- มาแล้ว PHP 5.3 พร้อมกับ error ที่ไม่คาดฝัน