Nem sok munkát publikálok, mert nem is nagyon szoktam publikálásra szánt anyagokat írni: Ez alkalommal kedvet kaptam ahhoz, hogy írjak egy kis alap, példa kódot egy igen hasznos dologgal kapcsolatban: ez pedig a SAMP szever monitorozása. Ennek alapjául a SAMP Wiki
szolgált, amelynek tartalma a gyakorlatlan szemnek elsőre egy bonyolult dolognak tűnhet, pedig valójában roppant egyszerű. Éppen ezért is írtam meg ezt a kis 100 soros kódot; hogy aki ki szeretné ezt a lehetőséget használni, de nem nagyon sikerül megérteni, az talán egy példán és némi magyarázaton keresztül megérti majd. Ezeken kívül természetesen található a neten rengeteg forráskód még ezzel kapcsolatban, amelyek sokszor komoly rendszerek, amely biztosítanak függvényeket a lekérdezések és műveletek egyszerű elvégzéséhez. Illetve találni kész, nagy terjedelmű, dizájnolt kódokat is. Azonban úgy gondolom, hogy hasznosabb az, ha az ember érti is a forráskódot és nem csak letölt egyet, illetve ha teljesen sajátot ír, a saját kódolási szokásaival, a saját szándékának megfelelően. Ez a példa pedig talán remek alapjául szolgálhat a dolog megértésének és egy egyedi kódba kezdésnek.
De talán szokásomhoz híven kicsit sokat szövegeltem, így ideje egy képen bemutatni az eredményt:
[hs width=222]
http://kephost.com/images/2014/11/20/example.png[/hs]
1. ábra - A képen egy, a SAMP kliens szerverlistázójából véletlenszerűn kiválasztott szerver adatai láthatók Semmi túlzott dizájn, csak egy kevéske HTML az olvashatóság értekében. Ti majd magatoknak a saját kódotokat úgy dizájnoljátok, ahogyan csak akarjátok. De most jön a lényeg, a kód:
<?php
/*
Készítette: Dfoglalo
Felhasználási feltételek: ne állítsa be úgy a kódot, mintha önmaga készítette volna.
Kelt: 2014.11.20.
*/
$ip = \"127.0.0.1\"; // A szerver IP címe
$port = \"7777\"; // A szerver portja
$socket = fsockopen(\'udp://\'. $ip, $port, $errorn, $errori); // Socket készítése
if($socket) // Ha a megnyitás sikeres
{
$packet = \'SAMP\'; // A SAMP packet kiválasztása
// Az IP címet és a portot hozzáadogatjuk a változóhoz
$packet .= chr($ip[0]);
$packet .= chr($ip[1]);
$packet .= chr($ip[2]);
$packet .= chr($ip[3]);
$packet .= chr($port & 0xFF);
$packet .= chr($port >> 8 & 0xFF);
fwrite($socket, $packet.\'i\'); // Elküldjük a packetet, benne a SAMP azonosítóval, az IP-vel és a porttal, valamint az i opcodeddal
fread($socket, 11); // A 11. bájttól kezdjük a beolvasást, mert ott találjuk az első kiírandó adatot
/* A 11. bittől kezdve kérdezhetjük le, hogy jelszóval van e védve a szerver.
Ennek a hossza 1 bit, tehát ekkora a hosszan is kérjük le az adatokat.
A visszakapott értéket ellenőrizzük és ha igaz, a szerver jelszóval van védve.
Ellenkező esetben természetesen a szerver nincs jelszóval védve. */
$password = ord(fread($socket, 1));
if($password) echo \'<b>A szerver <font color=\"red\">jelszóval van védve.</font></b><br>\';
else echo \'<b>A szerver <font color=\"green\">nincs jelszóval védve.</font></b><br><br>\';
/* A követkőzkben kiírjuk, hogy a szerveren hány játékos tartózkodik jelenleg hány slotból.
Mivel előtte lekérdeztünk egy bitet, így automatikusan továbbléptünk a következőhöz.
Ezáltal le tudjuk kérdezni akár a következő 2 bitet is, amely a játékosok számát adja vissza.
Ha ezzel is készen vagyunk, lekérdezhetjük a következő kettőt, amely a szerver slotok számát adja vissza. */
echo \'<b>Játékosok száma:</b> \' . ord(fread($socket, 2)) . \'/\' . ord(fread($socket, 2)) . \'<br>\';
/* A következő 4 biten lekérdezhetjük, hogy milyen hosszú a hostname.
Ezen lekérdezést eredményét deklaráljuk egy $strlen nevű változóba.
Utána jön maga a hostname. Hogy ezt le tudjuk kérdezni, meg kell tudnunk, hogy hány
bitnyi adatok kell most lekérdeznünk. Ezt mi már megtudtuk az előző lépés segítségével.
Így tehát egy kézzel beírt szám helyett a deklarált $strlen változót adjuk meg. */
$strlen = ord(fread($socket, 4));
echo \'<b>Hostname:</b> \' . fread($socket, $strlen) . \'<br>\';
/* Ugyanezen módszerrel lekérdezhetjük a gamemode nevét és a
mapnamet is, ugyanis ők következnek a sorban, a visszakapott bitek sorában. */
$strlen = ord(fread($socket, 4));
echo \'<b>Gamemode:</b> \' . fread($socket, $strlen) . \'<br>\';
$strlen = ord(fread($socket, 4));
echo \'<b>Mapname:</b> \' . fread($socket, $strlen) . \'<br><br>\';
/* Idáig tartottak az alap adatok, amelyeket az ember általában ki szokott íratni.
Azonban felhozok még 1-2 példát, ha nem porlbéma. Például azt, hogy hogyan kell
lekérdezi az egyes játékosok elérhető adatait. Íme.*/
fwrite($socket, $packet.\'c\'); // Már az c opcodeddal küldjük el a packetet
fread($socket, 11); // Szintén a 11. bájttól kezdjük a beolvasást
$players = ord(fread($socket, 2)); // Deklaráljuk a players változót, amely értéke egyenlő lesz az online játékosok számával
/* 0 játékos esetén ez a rész nem fog lefutni. Ha csak a ciklus létezne, nem
lenne rá feltétlenül szükség, mert a ciklusmag egyszer sem futna le, 0 játékos
esetén sem. Bár a ciklus megpróbálna lefutni, feleslegesen, amelyet jobb megakadályozni.
De jelen esetben főleg azért van rá szükség, hogy ne hozzunk létre feleslegesen egy
táblázatot, ha 0 játékos tartózkodik fent a kiválasztott szerveren. */
if($players > 0)
{
/* Táblázat megkezdése 5 pixeles margóval, a játékos lista megformázása érdekében */
echo \'<table celspacing=\"5\">
<tr>
<td><b>Név</b></td>
<td><b>Pont</b></td>
</tr>\';
for($i = 0; $i < $players; ++$i)
{
/* A kényelmesebb kommentezés érdekében deklaráltam néhány plusz helyi
változót, például a $score változóra nincs jelenleg szükség, ugyanis
kiírhattam volna rögtön a képernyőre az fread függvény által visszaadott adatokat. */
$strlen = ord(fread($socket, 1)); // Lekérdezzük a soron következő játékos nevének a hosszát
$player = fread($socket, $strlen); // Lekérdezzük a soron következő játékos nevét annak előzőleg lekérdezett hossza alapján
$score = ord(fread($socket, 4)); // Lekérdezzük a soron következő játékos pontjainak számát, a következő 4 bitről
/* Kiíratjuk a játékos nevét és a pontját. */
echo \'<tr><td>\' . $player .\'</td><td>\' . $score .\'</td></tr>\';
/* Ha még van(nak) hátra játékos(ok), akkor a ciklis nem kép ki és a ciklusmag újra lefut.
Azonban ekkor már túlléptünk néhány bitet, nevezetesen a soron következett játékos
nevének a hosszát, a nevét és a pontját tartalmazó biteket. Így legközelebb már az ezen
bitok után következő bitek fognak következni, amely már egy új játékos adati lesznek. */
}
echo \'</table>\'; // A táblázat lezárása
}
}
else echo \"A szerver nem elérhető.\";
fclose($socket); // Lezárjuk a kapcsolatot
?>
Nem a legprofibb kód, de megteszi. Egyébként egyedül azért nevezem ezt egy PHP szkriptnek, nem pedig egy tutorialnak, mert a szkript önmagában is felhasználható - és így is szeretném kiadni, mint felhasználható szkript, ha már megírtam - például arra, hogy valaki a szervere weboldalán kilistázza az éppen online játékosokat. Na meg a tutorial kicsit máshogy is nézne ki; alapból a fórum témában írnám meg, nem pedig kommentezve a kódban.
Letöltés -
Pastebin Remélem, hogy azért valakinek majd a hasznára válik.
Utóirat: lehet, hogy ezt a dOnitor megnevezést nem kéne erőltetnem, de már mindegy. :D
Üdvözlettel,
Dfoglalo
Valahol mintha láttam volna már az alsó részét.
Ez az egyik legegyszerűbb megoldás. Nem fogom átírni máshogy (már ha egyáltalán át lehet - nem hiszem, mert freaddel lehet beolvasni, meg kell adni a megnyitott socketet és a biteket és pont) csak azért, mert más már megoldotta esetleg így. Bár lehetne például így is:
echo \'<tr><td>\' . fread($socket, $strlen) .\'</td><td>\' . ord(fread($socket, 4)) . \'</td></tr>\';
Csak kommentezni szerettem volna.
Szép! :D
Elég szép munka
Szerintem az elején kimaradt egy explode:
$ip = \"127.0.0.1\"; // A szerver IP címe
Majd kicsivel utána:
$packet .= chr($ip[0]);
$packet .= chr($ip[1]);
$packet .= chr($ip[2]);
$packet .= chr($ip[3]);
Kettő közt kellene:
explode(\'.\', $ip);
Most néztem csak át rendesen a kódot, szépen megfogalmaztad, hogy hol mit csinálsz épp.
..
Most hülyeséget akartam kérdezni, de írás közben rájöttem :D
Az opcodeokról viszont írhattál volna többet is, hogy egyáltalán mi az, vagy hogy melyik mit csinál
Az opcodeokról viszont írhattál volna többet is, hogy egyáltalán mi az, vagy hogy melyik mit csinál
Van hozzá dokumentáció.
SA-MP-hoz van egy API
http://forum.sa-mp.com/showthread.php?t=104299
https://gist.github.com/Westie/234209