webForumDet fria alternativet

Timeout med fsockopen

11 svar · 383 visningar · startad av Erik Juhlin

Erik JuhlinMedlem sedan maj 200010 687 inlägg
#1
// Öppna en "file-socket" som använder sig av protokollet UDP,
// vänta på svar i 5.0 sekunder (timouten verkar inte fungera
// om webservern kör ett win32 OS, inte heller freeBSD?)
$fp = fsockopen("udp://$ip", $port, $errno, $errstr, 5.0);

Tydligen så funkar inte timeouten mot FreeBSD servrar. Går det att på något annat sätt att få scriptet att skriva ut ett felmeddelande efter ett litet tag istället för att det ska köra i en "evighet"..?

Erik JuhlinMedlem sedan maj 200010 687 inlägg
#2

Heja PHP... :l

PeddaMedlem sedan juni 20006 032 inlägg
#3

Hur ser koden ut efter den raden? Kör du fclose?

Erik JuhlinMedlem sedan maj 200010 687 inlägg
#4

Allt i filen... :)

<?php 
// FUNCTIONS 
/////////////////////////////////////////////// 

// Skapar en tid med mha. microtime 
function GetMicroTime() 
{     
    list($msec, $sec) = explode(" ", microtime()); 
    return ($sec + $msec); 
} 

// Hämtar 2st bytes och gör om dem till en Int16 
function getInt16($fp) 
{     
    $data = unpack("Sshort", fread($fp, 2)); 
    return $data['short']; 
} 

// Hämtar 4st byte och gör om dem till en Int32 
function getInt32($fp) 
{     
    $data = unpack("Lint", fread($fp, 4)); 
    return $data['int']; 
} 

// Hämtar 4st byte och gör om dem till en Float32 
function getFloat32($fp) 
{     
    $data = unpack("ffloat", fread($fp, 4)); 
    return $data['float']; 
} 

// Hämtar ett tecken och returnerar dess ASCII värde 
function getByte($fp) 
{     
    return ord(fread($fp, 1)); 
} 

// Hämtar ett tecken och returnerar det 
function getChar($fp) 
{     
    return fread($fp, 1); 
} 

// Hämtar tecken för tecken tills ett NULL-tecken hittas, 
// då returnerar den de hämtade teckena i form av en sträng 
function getString($fp) 
{ 
    while(1) { 
        $rchar = fread($fp, 1); 
        $r_string.= $rchar; 
        if(ord($rchar) == 0) 
            break; 
    } 
    return $r_string; 
} 

// Hämtar tecken för tecken tills ett \ tecken hittas (eller ett nulltecken), 
// då returnerar den de hämtade teckena i form av en sträng 
function getSlashString($fp) 
{ 
    while(1) { 
        $rchar = fread($fp, 1); 
        $r_string.= $rchar; 
        if($rchar == "\\" || $rchar == "\0") {             
            // Ta bort slashet (ersätt det med NULL) 
            $r_string = str_replace("\\", "\0", $r_string); 
            break; 
        } 
    } 
    return $r_string; 
} 

// Skickar 4 st ÿ som motsvarar en int32 med värded -1 
// följt av kommandot avslutat med ett NULL-tecken 
function sendCommand($fp, $Cmd) 
{ 
    fputs($fp,"ÿÿÿÿ".$Cmd."\0"); 
} 

// HTML START 
///////////////////////////////////////////////// 
?> 
<html> 
<head> 
<title>CS - Server Info</title> 
</head> 
<body> 
<font face="Courier"> 
<?php 
// MAIN CODE 
//////////////////////////////////////////////// 

// Kolla om vi har en ip och port variabel 

$ip = "212.73.160.51";
$port = "27015";

if(isset($ip) && isset($port)) { 
    // Öppna en "file-socket" som använder sig av protokollet UDP, 
    // vänta på svar i 5.0 sekunder (timouten verkar inte fungera 
    // om webservern kör ett win32 OS, inte heller freeBSD?) 
    $fp = fsockopen("udp://$ip", $port, $errno, $errstr, 5.0); 
     
    if (!$fp) { 
        // Nått gick snett, printa ut vad som gick snett 
        echo "ERROR: $errno - $errstr<br>\n"; 
    } else { 
        // Vi är nu connectade, kör våra kommandon 
         
        //////////////////////////////////////////// 
        // P I N G 
        //////////////////////////////////////////// 
        echo "<h3>Ping</h3>"; 
        // Hämta tid 
        $s_time = GetMicroTime(); 
        // Skicka pingkommando 
        sendCommand($fp, "ping"); 
        // Ta emot svar 
        getInt32($fp);    // Alltid -1 
        getChar($fp);    // Alltid 'j' 
        getByte($fp);    // NULL ??? 
        // Mät hur lång tid det tog och skriv ut det i millisekunder 
        echo "Ping: <b>".round((GetMicroTime() - $s_time) * 1000)."</b><br>"; 
         
        //////////////////////////////////////////// 
        // I N F O 
        //////////////////////////////////////////// 
        echo "<h3>Info</h3>"; 
        // Skicka info kommando 
        sendCommand($fp, "info"); 
        // Ta emot svar 
        getInt32($fp);    // Alltid -1 
        getChar($fp);    // Alltid 'C' 
        echo "Net address of server: <b>".getString($fp)."</b><br>"; 
        echo "Name of the host / server: <b>".getString($fp)."</b><br>"; 
        echo "Name of the map: <b>".getString($fp)."</b><br>"; 
        echo "Game directory: <b>".getString($fp)."</b><br>"; 
        echo "Game description: <b>".getString($fp)."</b><br>"; 
        echo "Active client count: <b>".getByte($fp)."</b><br>"; 
        echo "Maximum clients allowed: <b>".getByte($fp)."</b><br>"; 
        echo "Protocol version: <b>".getByte($fp)."</b><br><br>"; 
         
        //////////////////////////////////////////// 
        // P L A Y E R S 
        //////////////////////////////////////////// 
        echo "<h3>Players</h3>"; 
        // Skicka players kommando 
        sendCommand($fp, "players"); 
        // Ta emot svar 
        getInt32($fp);    // Alltid -1 
        getChar($fp);    // Alltid 'D' 
        $clients = getByte($fp); // Antal spelare 
        // Skriv ut info om våra spelare 
        for($i = 0; $i < $clients; $i++) { 
            echo "Client number / index: <b>".getByte($fp)."</b><br>"; 
            echo "Player name: <b>".getString($fp)."</b><br>"; 
            echo "Client's frag total: <b>".getInt32($fp)."</b><br>"; 
            echo "Client's total time in-game: <b>".round(getFloat32($fp))."s</b><br><hr width=100%>"; 
        } 
        if($clients == 0) { // Om inga spelare var activa, skriv det 
            echo "No active players<br>"; 
        } 
        echo "<br>"; 
         
        //////////////////////////////////////////// 
        // R U L E S 
        //////////////////////////////////////////// 
        echo "<h3>Rules</h3>"; 
        // Skicka rules kommando 
        sendCommand($fp, "rules"); 
        // Ta emot svar 
        getInt32($fp);    // Alltid -1 
        getChar($fp);    // Alltid 'E' 
        $rules = getInt16($fp); // Antal regler 
        // Hämta alla våra regler och skriv ut dem (regelnamn : värde) 
        for($i = 0; $i < $rules; $i++) { 
            echo getString($fp)." : <b>".getString($fp)."</b><br>"; 
        } 
        echo "<br>"; 
         
        //////////////////////////////////////////// 
        // D E T A I L S 
        //////////////////////////////////////////// 
        echo "<h3>Details</h3>"; 
        // Skicka details kommando 
        sendCommand($fp, "details"); 
        // Ta emot svar 
        getInt32($fp);    // Alltid -1 
        getChar($fp);    // Alltid 'm' 
        echo "Net address of server: <b>".getString($fp)."</b><br>"; 
        echo "Name of the host / server: <b>".getString($fp)."</b><br>"; 
        echo "Name of the map: <b>".getString($fp)."</b><br>"; 
        echo "Game directory: <b>".getString($fp)."</b><br>"; 
        echo "Game description: <b>".getString($fp)."</b><br>"; 
        echo "Active client count: <b>".getByte($fp)."</b><br>"; 
        echo "Maximum clients allowed: <b>".getByte($fp)."</b><br>"; 
        echo "Protocol version: <b>".getByte($fp)."</b><br>"; 
        echo "Type of server: <b>".(getChar($fp)=='d'?"dedicated":"listen")."</b><br>"; 
        echo "OS of server: <b>".(getChar($fp)=='l'?"linux":"win32")."</b><br>"; 
        echo "Password on server: <b>".(getByte($fp)?"Yes":"No")."</b><br>"; 
        $mod = getByte($fp); // Kör servern en mod? 
        echo "Is server running a mod?: <b>".($mod?"Yes":"No")."</b><br>"; 
        // Om servern kör en mod, hämta info om modden. 
        if($mod) { 
            echo "- URL for mod's \"info\" website: <b>".getString($fp)."</b><br>"; 
            echo "- URL for mod's download ftp server: <b>".getString($fp)."</b><br>"; 
            echo "- Unknown variable (byte): <b>".getByte($fp)."</b><br>"; 
            echo "- Mod version #: <b>".getInt32($fp)." (Correct?)</b><br>"; 
            echo "- Mod download size ( in bytes, approx. ): <b>".getInt32($fp)." (Correct?)</b><br>"; 
            echo "- Is the mod a server side only mod?: <b>".(getByte($fp)?"Yes":"No")."</b><br>"; 
            echo "- Does this server require you to have a custom client side .dll ( client.dll )?: <b>".(getByte($fp)?"Yes":"No")."</b><br>"; 
        } 
         
        //////////////////////////////////////////// 
        // I N F O S T R I N G 
        //////////////////////////////////////////// 
        echo "<h3>Infostring</h3>"; 
        // Skicka details kommando 
        sendCommand($fp, "infostring"); 
        // Ta emot svar 
        getInt32($fp);    // Alltid -1 
        echo getSlashString($fp)."<br>"; // Ska alltid vara "infostringresponse" 
        getByte($fp);    // NULL-tecken 
        // Nu tar vi emot 15*2 st Slashterminerade strängar 
        for($i = 0; $i < 15; $i++) { 
            echo ($i+1).": ".getSlashString($fp)." : <b>".getSlashString($fp)."</b><br>"; 
        } 
         
        // Då var vi klara så... 
        // Stäng våran "file-socket" 
        fclose($fp); 
    } 
} else { 
    // Skriv ut ett fint formular för att skriva in ett IP och en port 
    echo "<form action=\"hl-stats.php\" method=\"post\">\n"; 
    echo "IP &nbsp;&nbsp;<input type=\"text\" name=\"ip\" value=\"127.0.0.1\"><br>\n"; 
    echo "Port <input type=\"text\" name=\"port\" value=\"27015\"><br>\n"; 
    echo "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type=\"submit\" value=\"Visa server info\">\n"; 
    echo "</form>\n"; 
} 
?> 
</font> 
</body> 
</html>
stevenetMedlem sedan juni 20001 251 inlägg
#5

http://www.php.net/manual/en/function.stream-set-timeout.php
Prövat? "This is a must for use with fsockopen and Half-Life Servers"

Erik JuhlinMedlem sedan maj 200010 687 inlägg
#6

Så stream_set_timeout($fp, 2); ska placeras ungefär vid // Vi är nu connectade, kör våra kommandon?

stevenetMedlem sedan juni 20001 251 inlägg
#7

Direkt efter:
$fp = fsockopen("udp://$ip", $port, $errno, $errstr, 5.0);

Erik JuhlinMedlem sedan maj 200010 687 inlägg
#8

Så är det ju inte på php.net sidan...

stevenetMedlem sedan juni 20001 251 inlägg
#9

Men om du placerar den vid:
// Vi är nu connectade, kör våra kommandon?
så är du ju redan ansluten. Varför ska du då ha timeouten?

Erik JuhlinMedlem sedan maj 200010 687 inlägg
#10

Kolla på php.net så ser du att de först kollar om det har upprättats en anslutning...

stevenetMedlem sedan juni 20001 251 inlägg
#11

Hittade följande på http://www.php.net/manual/en/function.fsockopen.php
"The error will only become apparent when you read or write data to/from the socket. The reason for this is because UDP is a "connectionless" protocol, which means that the operating system does not try to establish a link for the socket until it actually needs to send or receive data. "

Vilket borde betyda att kommandot ska vara efter pingen. Jag ber om ursäkt. Angående exemplet på länken jag gav tidigare så gällde det väl skickning av datan "GET / HTTP/1.0\n\n".

Annat att notera är:
"Note: The timeout parameter was introduced in PHP 3.0.9 and UDP support was added in PHP 4. "

stevenetMedlem sedan juni 20001 251 inlägg
#12

Exempel:

<?php
$fp = fsockopen("udp://$ip", $port, $errno, $errstr, 5.0); 
     
    if (!$fp) { 
        // Nått gick snett, printa ut vad som gick snett 
        echo "ERROR: $errno - $errstr<br>\n"; 
    } else { 
        // Vi är nu connectade, kör våra kommandon 
        sendCommand($fp, "infostring"); 
        $str = fread($fp, 220);
        if (!$str) {
            echo "Couldn't connect.";
            exit;
        }
        else {
       //////////////////////////////////////////// 
        // P I N G 
        //////////////////////////////////////////// 
?>

Glöm inte bort en extra } i slutet av skriptet..

136 ms totalt · 3 externa anrop · v20260731065814-full.30151723
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
133 ms — hämta tråd, inlägg och bilagor (db)