5 Síťová komunikace
5.1 Obecné informace o síti
Síťová komunikace používá ke komunikaci přes síť protokol TCP/IP a je založená na klient/server architektuře. Před zahájením síťové hry je na serveru vybrána mapa, na které se bude hrát a následně se k serveru připojují klienti. Žádný z těchto klientů nemá oproti ostatním žádné práva nebo povinnosti navíc. Naopak postavení serveru je značně důležitější, neboť se zde provádí všechny výpočty hry - tím se zamezí i pokusům hráčů přizpůsobit si vývoj ve hře k vlastnímu prospěchu modifikací klienta na své straně.
Jelikož se používá architektura klient/server, jsou navázáná spojení pouze mezi každým klientem a serverem. Žádná jiná komunikace není povolena. Toto má některé výhody avšak i omezení. Výhodou je, že ke hře se může uživatel připojit, i když je mezi ním a herním serverem aktivní firewall, který by zamezil pokus o připojení kohokoliv na jeho stanici. Nevýhodou může být nutnost posílat všechny zprávy i mezi klienty přes server. Ve většině případů ve hře však o zbytečnou komunikaci nejedná - příkladem může být situace, kdy klient se rozhodne táhnout svoji jednotkou na jiné pole, pošle zprávu serveru, ten vyhodnotí a pokud lze akci provést, pošle zprávu všem klientům. Stejný počet zpráv by bylo třeba i v případě, že by bylo navázáno spojení i mezi klienty (neboť veškeré výpočty se provádí na serveru).
5.2 Třídy
Základní nástroje pro práci se sítí jsou třídy TServer a TClient. Instance těchto tříd jsou v každé aplikaci nejvýše jednou s tím, že TServer, reprezentace serveru hry, je spuštěn nejvýše jednou mezi všemi aplikacemi zapojenými do hry. Obě tyto třídy jsou potomky třídy TComm, ve které je implementováno posílání a přijímání zpráv a fronta požadavků k odeslání. Do této fronty ukládá každý účastník síťové komunikace svoje zprávy k odeslání a tato fronta je pak ve vlákně procházena a zprávy postupně odesílány. V dalším vlákně pak dochází k příjmu zpráv. Z vlastností protokolu TCP/IP stačí jeden zásobník na příjem zpráv na každé straně každého připojení. Každý objekt TClient má buffer přímo jako privátní atribut, server pak využívá buffer ze struktury TNodeInfo, kde se nacházejí informace o připojených klientech, nejdůležitější je pak atribut clientId, jednoznačně určující připojení klienta. Ve chvíli, kdy některá strana obdrží celou zprávu, jí odesílá pomocí Message Systému modulu, pro který je daná zpráva určena. Maximální velikost zprávy je omezena konstantou MAX_SIZE_OF_MESSAGE. Pokud je zpráva delší, bude odeslána po částech a na straně příjemce bude opět skládána. I kratší zpráva však může být rozdělena vlivem OS.
Server vytváří ještě další vlákno, kde přijímá pokusy o připojení klientů k serveru. To se děje do doby, dokud počet klientů nepřesáhne počet, který byl zvolen při vytváření tohoto objektu. Pak jsou již další pokusy o připojení odmítány. Při odpojení klienta před zahájením hry se vymažou všechny informace o jeho připojení, avšak informace se nemažou, pokud hra již začala. Při následném pokusu o znovu-připojení klienta se nejprve zkusí identifikovat podle jeho jména profilu a až v případě, že takový profil volný není, je tento pokus o připojení odmítnut. K odmítnutí následně dochází pokaždé, pokud 4. parametr konstruktoru objektu TServer int reconnect je nastaven na 0.
Poslední vlákno, které jak server tak i klient vytváří slouží na odesílání zprávy - "ping", sloužící k zjišťování, zda druhá strana je stále aktivní. Server vytváří toto vlákno ihned ve chvíli inicializace (pokud je nastaveno, že se jedná o síťovou hru) a tyto zprávy posílá na všechny klienty, kteří jsou připojeni jen vzdáleně, klient pak pouze na server a vlákno vytváří, až ve chvíli, kdy obdrží od serveru jméno profilu (viz. Inicializace). K aktivaci slouží v obou třídách metoda startPing, aktualizace času poslední známé informace o činnosti protistrany se pak provádí metodou setPing. Související konstanty jsou PING_TIME, určující jakou periodu budou jednotlivé odesílání zpráv ping mít, MAX_TIMEOUT maximální doba nezjištěné činnosti protistrany, po níž se spojení ukončuje a PING_ENABLED zda odesílání a kontrolu činnosti vůbec provádět.
Diagram 5.1: Připojování klientů k serveru se zobrazením vláken puštěných serverem (Přijímající, Připojující a Odesílající) a klienty (Přijímající, Odesílající).
Diagram 5.2: Odeslání zprávy od Klienta 1 na Server a od Serveru na Klienta 2.
Jelikož hra dovoluje i lokální hru - více hráčů na jednom počítači, bylo odesílání zpráv v tomto případě přizpůsobeno faktu, že lokální klient a server jsou v jednom paměťovém prostoru. Z vlákna, které slouží k odesílání zpráv, se neposílá zpráva přes loopback (IP adresa 127.0.0.1 reprezentující stanici na které uživatel pracuje), avšak je odeslána zpráva přímo adresátovi pomocí Message Systemu. I v tomto případě se inicializuje pouze jedna instance TClient a to s parametrem lokální hry nastavené na 1.
Třetí třída, využívaná v síťování je TLocator. Činnost této třídy se vymezuje na hledání okolních síťových her ať již LAN nebo i her přes Internet. V případě, že má aktuálně zvolený profil nastaveno odesílání informací o hře (její oznamování), je při zahájení činnosti Serveru odeslán požadavek

        GET /main.php?ip=y&mn=[jméno_mapy]&p=[počet rolí v této mapě] HTTP/1.1
        Host: 8k.vta.cz

na webový server na adrese http://8k.vta.cz/. Zde se informace uloží. Každých 5 minut (resp. ANNOUNCE_TIME sekund) dojde k opětovnému odeslání dat, aby se záznam udržel aktivní. Toto vysílání pokračuje do doby, dokud není server zrušen nebo nezačne hra. Dále také dochází k broadcastu UDP diagramů po lokální síti. Tyto zprávy mají již tvar shodný se strukturou dat, které přijímá TLocator z webového serveru a to

        <K8>
          <host>
            <mn>[jméno_mapy]</mn>
            <p>[počet rolí v této mapě]</p>
          </host>
        </K8>

Rozdíl činní atribut IP, který je obsažen ve zprávě z webového serveru, avšak který se, v případě lokálních her, sbírá z odesílatele vlastního UDP paketu. Druhý rozdíl činí indexace hostitelů - v případě stahování informací z webového serveru se získají všechna data najednou, tagy host pak jsou číslované od 1 dále. V případě UDP diagramů toto číslování neexistuje a k zařazování do tabulky okolních her dochází postupně ve speciálním vlákně vytvořené objektem třídy TLocator. Jelikož se UDP diagramy centrálně neukládají, je jejich odesílání častější, přesně každých ANNOUNCE_LAN_TIME (6) sekund. Proto se může stávat, že lokální hra se uživateli zobrazí nikoli hned po vyhledání okolních her, avšak za jistou relativně krátkou chvíli. Ukončení odposlouchávání UDP paketů dochází ve chvíli kdy objekt zaniká nebo když se uživatel pokusí připojit na nějaký server. To je možné díky zprávě MSG_NET_STOP_SEARCHING_LAN. K načítání informací z webového serveru dochází pouze jednou po požadavku o načtení. Server pak ukončuje inzerci své hry ve chvíli, kdy je hra zahájena nebo zrušena. Jak na oznamování her v LAN síti, tak na oznamování her přes internet, si server vytváří dvě další vlákna.
Vlastní zahájení hledání okolních her na klientovi resp. stažení informací z webového serveru nastane po odeslání zprávy MSG_SEARCH_GAMES. Okolní moduly jsou pak informovány pomocí zprávy MSG_NET_OTHER_GAMES_INFO (pro Internetové hry) a při každé změně v lokálních hrách také pomocí zprávy MSG_NET_LAN_GAMES_INFO. Obě zprávy odkazují na privátní atribut pole DA struktur TGames, obsahující informace o hře - IP adresu serveru, jméno mapy a počet rolí v mapě.
5.3 Inicializace
Inicializace modulu síťové vrstvy aplikace se prování voláním funkce NETinit. Inicializace serveru se provádí zasláním zprávy MSG_NET_STARTSERVER, inicializace klienta pomocí MSG_NET_STARTCLIENT.
Diagram 5.3: Průběh připojování klienta k serveru.
Připojení klienta na serveru vyvolá synchronizační proceduru, při které se klient dozví o svém clientId a server o jménu profilu, který je na klientovi zvolen. Server očekává, že první zpráva, která po síti přijde, je MSG_NEW_CONNECTION_SYNCHRO2. Pokud tak není, je spojení s klientem ukončeno. Následuje zapsání jména profilu klienta na serveru a rozeslání všem klientům informaci o novém připojení. Proto je rozeslána zpráva MSG_CLIENT_CONNECTION_INFO, ve které si všechny objekty TClient aktualizují seznam připojených účastníků. Tato zpráva, narozdíl od ostatních, je posílána pro všechny lokální hráče jen jednou. Informací o všech připojených klientech se v TClient ukládají do struktur TClientInfo, které se od TNodeInfo liší ve dvou věcech - TClientInfo neobsahuje přijímací buffery a jiné pomocné údaje a informace o lokální připojení je vždy vnímána vzhledem ke každému objektu.
Dále se posílá zpráva pro všechny moduly MSG_NEW_CONNECTION_REPORT. Přidání lokálního klienta (tj. dalšího hráče nebo umělé inteligence) se volá pomocí zprávy MSG_ADD_LOCAL_CLIENT (nikoli inicializací další instance objektu TClient) na místě, kde běží server. Poslední zpráva zde používaná je MSG_NET, která je posílána, když je zavolaná metoda TPackage::send() a je zachytávána v síťovém transcieveru. Posláním této zprávy začíná vlastní síťový přenos.
Přidávání lokálního klienta místo vlastního vytvoření síťového spojení klienta a serveru je jediný rozdíl mezi komunikací lokální a síťovou a dále je rozlišován pouze v síťové vrstvě aplikace.
5.4 Dealokace
Dealokace pouze objektu klienta se provádí zasláním zprávy MSG_NET_STOPCLIENT, zpráva MSG_NET_STOP pak dealokuje objekt serveru i klienta - resp. pouze ten, který je v aplikaci spuštěn. Pokud se ukončuje (dealokuje) objekt klienta, je zároveň ukončeno hledání okolních her pomocí objektu Locator. Ukončení celého modulu se pak zařídí pomocí volání funkce NETdestroy.
5.5 Přenášená data
Data jsou přenášená v XML formátu. Po zavolání metody TPackage::send() (viz popis třídy TPackage a jejího potomka TPackSmall) jsou k datům uloženým v TPackage přiloženy dodatečné informace - o adresátovi, o odesílatelovi (tato informace se uchovává dvakrát, obsahuje za prvé skutečného odesílatele a za druhé "přeposílatele" - ten se mění na server v případě, že se posílá zpráva od jednoho klienta k druhému), id transcieveru na který se má přišlá zpráva směřovat a dále zpráva obsahuje informaci o indexu struktury, kterou v sobě zpráva obsahuje. Následně se objekt "odešle" přes systém zpráv na síťovou vrstvu. V případě, že je makro COMPRESS_ACTIVE nastavena na 1, jsou data zkomprimovaná pomocí knihovny zlib. Před vlastními daty je odeslána krátká XML zpráva s informací o jejich velikosti. Tato zpráva předchází každému přenosu dat přes síť a není nikdy komprimovaná. Její velikost je vždy 22Bytů. Pokud se používá komprese, informace v ní obsahuje velikost komprimované zprávy a nikoliv rozbalené. Pomocí této krátké informace se nechají od sebe oddělit jednotlivé zprávy. O její generování a přijímání se starají "nízko úrovňové" metody recvFrom a sendTo z třídy TComm.