Jest to blog poświęcony nowoczelnym technologiom ułatwiającym tworzenie aplikacji internetowych. Znajdziesz tutaj porady na temat CSS3, JavaScript, designu, web-usability, standardów W3C.
Cześć! Nazywam się Michał Środek. Z zawodu programista php, z zamiłowania gitarzysta oraz fanatyk GNU/Linuksa(openSUSE® w laptopie). W branży aplikacji internetowych od 9 lat. Prywatnie bez dzieci i kota.
Pracuję wciąż nad własnym elastycznym i wydajnym frameworkiem MVC, kilkoma portalami internetowymi oraz mniejszymi bibliotekami php. Czekam na wasze opinie, zgłoszenia błędów oraz pomysły na dalszy rozwój.
Ta część strony jest w trakcie budowy a moje prace tymczasowo niedostępne.
W przypadku pytań, ofert pracy oraz ciekawych pomysłów proszę się ze mną kontaktować. Możesz mnie znaleźć i wysłać PW na php.pl(SHiP), jamendo.com(michalsrodek), goldenLine.pl, facebook.com lub nk.pl
Pisząc grę internetową trzeba zastanowić się nad sposobem komunikacji między graczami oraz bazą danych. W przypadku aplikacji przeglądarkowych dużego wyboru nie ma. Praktycznie wszystkie gry wykorzystują technologię AJAX. Jak to działa w praktyce? Nie za dobrze. Spróbujmy stworzyć coś dużo bardziej wydajniejszego.
AJAX to rozwiązanie jednostronne. Klient prosi serwer o pewne informacje, a ten je wysyła użytkownikowi. Serwer nie posiada dokładnych informacji na temat ilości aktualnie połączonych użytkowników oraz nie może wysłać do żadnego z nich samodzielnie żadnej informacji(tj. może jedynie odpowiadać na ich zapytania).

Kocham robić te fajne obrazki i choć nie mają one niczego wspólnego z UML-em mam nadzieję, że jesteś w stanie je odczytywać
Przeanalizujmy przykład czatu internetowego w którym mamy trzech użytkowników(Client1, Client2, Client3). Pierwszy z nich chce wysłać informację do trzeciego. Wygląda to następująco:
Jak widać wykonywanych jest wiele niepotrzebnych zapytań. Każdy z klientów musi stale wysłać zapytanie do serwera co w przypadku małego czasu może powodować spore zużycie procesora serwera. W sytuacji, gdy czas będzie większy w grze pojawią się lagi. Jak ten problem rozwiązuje się w „normalnych“ grach internetowych? Używane są gniazda.

Szerokie linie oznaczają nasłuchiwanie serwera oraz klientów
Każdy z klientów musi ustanowić połączenie z serwerem. Serwer dla każdego z nich tworzy gniazdo za pomocą którego w dowolnym momencie może wysłać informację do jednego z użytkowników.
Wygląda to tak:
W odróżnieniu do technologi AJAX w tym przypadku nasz serwer napisany w php musi ciąglę nasłuchiwać, a więc proces tego skryptu musi być cały czas uruchomiony. W tym celu tworzy się pętlę nieskończoną, którą cięgle sprawdza stan gniazda serwera.
Spróbujmy stworzyć pierwszy działający serwer. Nie będzie on pozwalał na przekazywanie danych innym użytkownikom, a połączenia nie będą utrzymywane.
<?php set_time_limit(0); class GameServer { private $master; private $address; private $port; private $maxClients; public function __construct($address = '127.0.0.1', $port=14117, $maxClients = 10) { $this->address = $address; $this->port = $port; $this->maxClients = $maxClients; $this->master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_bind($this->master, $this->address, $this->port); socket_listen($this->master); while(true) { // akceptujemy połączenie, tworzymy gniazdo $socket = socket_accept($this->master); // odczytujemy informacje z gniazda $input = socket_read($socket, 1024); // przygotowujemy dane do wysyłki $output = 'Wyslales do serwera: '.$input.chr(0); // Wysyłamy dane użytkownikowi socket_write($socket, $output); // zamykamy połączenie z użytkownikiem socket_close($socket); } } public function __desctruct() { // zamknięcie głównego gniazda socket_close($this->master); } } $gameServer = new GameServer(); ?>
Tworzymy obiekt $gameServer. W konstruktorze możemy podać kilka parametrów: adres i port pod jakim serwer będzie nasłuchiwał oraz maksymalną ilość użytkowników(ta zmienna nie jest używana w tym przykładzie lecz przyda się później).
W przypadku IP w wersji czwartej do dyspozycji mamy 216 portów. Te o numerach poniżej 1024 wymagają uprawnień administracyjnych. W większości przypadków są one już zarezerwowane dla innych usług(np. 80 dla http, 23 dla ftp, 21 dla telnet itd.). Najwygodniej jest po prostu ich nie ruszać.
Do zmiennej $this->master zapisywane jest główne gniazdo serwera tworzone za pomocą socket_create(). To ono będzie odbierało wszystkie informacje przychodzące od innych użytkowników. Co oznaczają parametry wewnątrz?
W naszym przykładzie stworzyliśmy gniazdo wykorzystujące protokół TCP. W kolejnej lini informujemy nasze gniazdo pod jakim adresem i jaki port ma nasłuchiwać. Gdy to określimy uruchamiamy nasłuchiwanie.
Ten proces jest bardzo prosty. Stworzona została pętla nieskończona, która przy każdym obrocie akceptuje gniazdo przychodzące. następnie odczytuje z niego dane, odsyła je do użytkownika oraz zamyka połączenie. Serwer uruchomiony raz będzie działał w nieskończoność(prawie w nieskończoność
) więc ważne jest aby wyłączyć sprawdzanie czasu wykonywania się skryptu. W tym celu w pierwszej linijce kodu widnieje wywołanie funkcji set_time_limit()
Uruchom konsolę z dwoma zakładkami. Aby uruchomić nasz serwer w pierwszej wpisz:
php server.php
W drugiej spróbujmy aktywował połączenie
hellson@hellson:~> telnet 127.0.0.1 14117 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. Hello Wyslales do serwera: Hello Connection closed by foreign host. hellson@hellson:~>
W przypadku zamknięcia skryptu wykonany zostanie destruktor zamykający gniazdo główne.
Mam nadzieję, że ten artykuł ułatwił ci zrozumienie idei gniazd. Już jutro kontynuacja tematu. Ulepszę kod serwera tak aby odbierał informacje od różnych użytkowników jednocześnie. Połączenie będzie utrzymywane aż do momentu wpisania „exit“ przez użytkownika.
To nie jest dobry sposób na utrzymanie trwałego połączenia z serwerem, weź pod uwagę że np. Apache dla każdego klienta/połączenia tworzy nowy wątek, teraz niech połączy się 200–500 klientów i … administrator pomyśli że ktoś mu DOSa robi
— ogólnie zajedziesz tym maszynę.
Komentarz by pfugiel — 14 maja 2010, 11:40
ps. czemu nie ma obsługi Gravatar (http://gravatar.com) ?
Komentarz by pfugiel — 14 maja 2010, 11:42
a) Teoretycznie tak ale powiedz mi w którym momencie użyłem serwera apache?
Wykonuję skrypt php jako skrypt powłoki pomijając tym samym całą otoczkę apachową. Serwer się nie zapcha. Zadziała to jak zwykły serwer np. gry counter-strike instalowany często na maszynach linuksowych(a przynajmniej kiedyś tak było).
PS: Gravatar działa. Sprawdzilem i okazało się, że podałeś złego maila(tj. hashe się nie zgadzają z tym linkim, który podałeś jako adres URL).
Komentarz by Michał Środek — 14 maja 2010, 12:26
Nie wiem czy pisanie serwera w php to dobry pomysł, ja bym wybrał raczej c lub python, no chyba, że pph wybrałeś tylko na potrzeby edukacyjne
Ciężko będzie też znaleść hosting, który pozwoli Ci utrzymywać własną instancje serwera, potrzebny będzie albo dedyk albo vps a to troche kosztuje
Komentarz by Maciej Wiczołek — 14 maja 2010, 12:35
Serwer zostanie przepisany najprawdopodobniej do Javy lub Pythona. Aktualnie po prostu nie mam czasu zagłębiać się w ten temat. Na początek PHP wystarczy tym bardziej, że radzi sobie całkiem nieźle.
Komentarz by Michał Środek — 14 maja 2010, 12:37
Java to dobry język ale na serwer za mało wydajny
Komentarz by Maciej Wiczołek — 14 maja 2010, 14:27
Wykorzystujesz ten serwer w jakiejś konkretnej produkcji, czy to czysto „akademicki“ test?
Komentarz by Tomasz Kowalczyk — 15 maja 2010, 0:10
Opieram to o moje aktualne postępy przy pisaniu własnej gry. Tak więc jest to sensowny i działający kod
.
Komentarz by Michał Środek — 15 maja 2010, 0:35
Wiem, że pewnie jestem „niedoinformowany“, ale można to gdzieś zobaczyć, jakiś serwer testowy, czy coś podobnego? Co to za gra, napiszesz coś o niej?
Komentarz by Tomasz Kowalczyk — 15 maja 2010, 0:58
http://srodek.info/blog/215/nowy-projekt-na-biurku
W skrócie: gra dla wielu graczy w czasie rzeczywistym napisana w PHP + HTML5 + miejscami xHTML(jego będę starał się unikać). Mam pomysł na jedną małą grę i jedną dużą. Co z tego wyjdzie zobaczymy
.
Komentarz by Michał Środek — 15 maja 2010, 1:18
Myślę, że PHP jak najbardziej nadaje się do tego typu projektu. W końcu i tak najwęższym gardłem będzie baza danych, a konkretnie dyski twarde. Nie ważne czy gra będzie w PHP, Java czy nawet C++
Zastanawia mnie jak rozwiążesz kwestie skalowalności. Bo jeden serwer wystarczy na 20tyś userów max. A przy takiej ilości graczy koszty mogą sie nie zwrócić.
Rozważałeś rozwiazania w stylu Amazon Web Services?
Komentarz by kalkulator kredytowy — 15 maja 2010, 23:32
Ja nie mam aż takiego rozmachu
aby mieć 20tys graczy wiec o AWS w ogóle nie myślałem. Co do obciążeń — informacje gry będę trzymał w pamięci współdzielonej tak aby nie obciążać dysków. Aktualizacje do bazy nie będą robione z każdą akcją bo będzie ich po prostu za dużo. Raczej będę to robił partiami — np. po zakończeniu jakiegoś etapu na danej mapie(np. zabicie jednostki wroga) lub w przypadku rozłączenia się gracza(co łatwo wykryć, w końcu socket sie zamyka). Ale i tak nie ma co gdybać — wszystko wyjdzie w praniu
.
Komentarz by Michał Środek — 16 maja 2010, 0:09
Jak na to co zacząłeś tutaj opisywać pasowało by zarzucić definicją czym jest AJAX… gdyż AJAX to nie tylko odpytywanie serwera co 1s… miałem się trochu rozpisywać ale… i u Ciebie nie ma spójności… piszesz o AJAX i temat urywasz, zmieniasz na stronę serwerową a pytanie?? co zadaje tu zapytanie?? flash?, AJAX — czyli w dużym uproszczeniu JS lub DHTML??… mniejsza o tym…
w komentarzach trochę pisałem o AJAX’ie [i jak to kolega Batman ocenił wygląda to jak sockety]:
http://wilgucki.blogspot.com/2010/04/komunikacja-z-serwerem-w-czasie.html
Komentarz by zegarek84 — 17 maja 2010, 2:04
Wychodzę z założenia, że każdy się orientuję czym jest AJAX(a jeśli nie wie to zawsze jest dostępna Wikipedia). Po prostu chciałem zrobić jakiś wstęp, pokrótce pokazać, że jest lepsze rozwiązanie tj. bardziej optymalne w porównaniu do tego czego używa większość programistów gier www. Oczywiście nie oznacza to, że AJAX-a nie będę w ogóle używał. Jak łatwo się domyśleć pojawi się trzecia część artykułu, w której opiszę zaprogramowanie klienta
.
Co do mojego serwera — zapytania będzie zadawał czysty JavaScript. Nie lubię flexow itp. Unikam zamkniętych rozwiązań jak ognia.
Komentarz by Michał Środek — 17 maja 2010, 2:26