Flash: Webová Peer-to-Peer aplikace
Flash není jen animace, reklamy, Flex, reklamy, video a reklamy. Flash player v sobě obsahuje věci, které byste pravděpodobně nečekali, jako je podpora P2P. Ta je ve Flashi od roku 2008 a lze ji použít ve webových aplikacích, kde může ušetřit obrovské množství přenesených dat, a to nejen při streamování videa.
P2P ve Flashi je dokonalou ukázkou jeho technické pokročilosti. I když se podpora datuje do roku 2008 (k termínu uvedení Flash Playeru 10), samotná diskuse na toto téma začala již v roce 2006. Později Adobe koupilo firmu Amicima, která pracovala na pokročilých P2P řešeních.
V kontextu Flashe se jedná o pokročilé téma, které příliš lidí zatím nezná, ale které si postupně získává čím dál větší kredit.
P2P
Když se řekne P2P, tak si většina lidí představí sdílení souborů a možná instant messaging či VoIP. Málokdo si však už představí např. distribuovanou televizi (Joost), distribuci živých streamů či reálný užitek ve webových aplikacích.
Ano – P2P je především obrovská úleva pro poskytovatele obsahu. Uživateli jako takovému je to víceméně jedno (ten pouze konzumuje obsah), ale i on ocení, že mu streamovaná data posílá kolega z vedlejšího domu se silnější linkou – a plynuleji – než přetížený server z USA.
Základní informace o P2P ve Flashi
Stavebním kamenem je protokol RTMFP (Real Time Media Flow Protocol), který je postavený na UDP, což je rozdíl oproti otevřenému protokolu RTMP (Real Time Messaging Protocol) postaveném na TCP. UDP je mnohem vhodnější na aplikace typu VoIP či video přenosy, protože má menší latenci, ale mohou se v něm objevit ztráty. Data jsou v RTMFP šifrována pomocí 128-bit AES. Podporuje také IP Mobility – v případě změny připojení či IP adresy se spojení automaticky znovu naváže. Dále RTMFP podporuje NAT Traversal, tudíž nemusíte mít veřejnou IP adresu.
Typy P2P sítí (Point-to-Point, Swarming, Application-Level-Multicast, DHT):

Zjednodušeně jsou ve Flashi jsou dva základní přístupy pro práci s P2P:
Point-to-Point
Umožňuje propojit 2 klienty mezi sebou a posílat data mezi nimi. Nicméně můžete propojit i více klientů mezi s sebou, ale každé spojení vyžaduje separátní NetConnection, resp. NetStream. Tento přístup je k dispozici ve Flash Playeru 10 a je v praxi složitější než přístup pomocí skupiny.
Skupina
K dispozici od Flash Playeru 10.1. Vytvoříte skupinu klientů (NetGroup), klienti se do ní připojí a můžou přijímat a odesílat data ostatním klientů této skupiny. K dispozici je několik metod:
- Directed Routing: obdoba DHT (Distributed Hash Table), vyžaduje stabilní síť se správnou topologií a umožňuje posílat zprávy specifickým klientům v síti
- Posting: odeslání zprávy (objektu) všem klientům ve skupině
- Multicast: odeslání datového streamu klientům (zpravidla Audio, Video), pro Multicast se používá třída NetStream
- Object Replication: zajišťuje doručení zpráv, UDP je ztrátový protokol a v případě Postingu nemáte stoprocentně zaručené, že všechny zprávy přijdou
Posting a Multicast jsou si velmi podobné. Posting je však navržený pro odesílání malých dat (chat) velkým množstvím odesilatelů (senders), zatímco multicast je spíš vhodný pro odesílání velkého množství dat (audio/video) menším počtem odesilatelů (broadcasters). Rozdíl je pouze v režii, která zajišťuje odeslání a doručení. Tato režie je v případě multicastu větší.
Unicast vs. Multicast
Většina čtenářů se už s těmito pojmy setkala. Krátce si je přiblížíme v kontextu Flashe.
Unicast je oddělený stream dat pro každého klienta, většinou od serveru ke klientovi. Když váš živý stream s 1 Mbps sleduje 1000 lidí, váš server pak odesílá 1 Gbps. Když vysíláte koncert pro 20.000 lidí (což je tak běžná online sledovanost známějšího koncertu), potřebujete cca 10 serverů + několik backup/peak serverů.
Multicast je distribuce streamu v rámci nějaké sítě. Tato síť může mít buď nativní podporu IP Multicastu (většinou v interní síti, na internetu příliš nefunguje), nebo se vytvoří tzv. Application-Level-Multicast (P2P Multicast), a nebo se vytvoří tzv. Fusion (fúze IP Multicastu a P2P Multicastu). IP Multicast je vždy výhodnější, ale musí mít podporu na straně routerů a musí být nastaven.
Distribuce streamu v multicastu pak funguje tak, že z vašeho serveru odešlete 1 Mbps stream, který se rozdistribuuje v rámci multicastové skupiny na klienty. Těch klientů může být i 20 000, ale z vašeho serveru jde pouze a stále jen 1 Mbps.
Jak P2P ve Flashi funguje
O propojení účastníků – peerů – se stará Adobe Stratus – tzv. Hosted Rendezvous Service – jinými slovy služba od Adobe, která zprostředuje „rande“ mezi peery. Peer se nejprve připojí na Stratus a přeloží svou adresu do unikátní informace, tzv. fingerprintu. Pomocí tohoto fingerprintu se pak identifikuje ostatním peerům. Ve Flash Playeru 10 propojujete peery nikoli pomocí IP adres, ale pomocí fingerprintů. V novém Flash Playeru 10.1 vytvoříte pouze skupinu a o fingerprinty se už nestaráte, jejich výměna se zprostředkuje na pozadí.
Základní schéma propojení dvou peerů pak vypadá zhruba takto: Peer si zažádá o fingerprint, ten předá nějakým způsobem druhému peeru, a druhý peer se může k tomuto fingerprintu připojit. Konkrétní forma předání fingerprintu záleží už na vaší vlastní implementaci.

Pavel Šimek vytvořil jednu z prvních P2P her ve Flashi – Mlýn. Můžete si ji zkusit zahrát a ověřit si fungování fingerprintů a P2P v praxi. Zalogujete se pod nějakým jménem, tím se vám vytvoří odkaz obsahující fingerprint, tento odkaz otevřete v druhém okně (v jiném prohlížeči, na druhém počítači doma, předejte jej kamarádovi, …), zadáte jméno a hra se spustí – hru tak hrajete ve dvou oknech prohlížeče (popř. s kamarádem).
P2P prakticky
V následující ukázce vytvoříme jednoduchý P2P chat pomocí skupin – konkrétně použijeme Posting. Budeme tedy cílit už na Flash Player 10.1.
K vytvoření budeme potřebovat
- Flash Player 10.1
- Povolené UDP na firewallu (standardně bývá)
- Flash Builder 4
- Stratus developer key – Vystavíte zde, zalogujete se pomocí vašeho Adobe ID
- playerglobal.swc pro Flash Player 10.1 – musí být nalinkován do projektu
Krok 1: Přípojíme se k serveru
private const SERVER:String = "rtmfp://stratus.adobe.com/";
private const DEVKEY:String = "STRATUS-DEVELOPER-KEY";
private var nc:NetConnection;
private function connect():void{
nc = new NetConnection();
nc.addEventListener(NetStatusEvent.NET_STATUS,netStatus);
nc.connect(SERVER+DEVKEY);
}
Krok 2: Nadefinujeme skupinu
Skupina má jméno a nastavení, výsledkem je řetězec, který vrátí funkce groupspecWithAuthorizations(). K dispozici je i groupspecWithoutAuthorizations(). Rozdíl je, že když nastavíte heslo pro Posting nebo Multicast tak groupspecWithoutAuthorizations je receive-only, nemůže tedy odesílat data, groupspecWithAuthorizations analogicky může. My data odesílat chceme, proto použijeme groupspecWithAuthorizations.
private function setupGroup():void{
var groupspec:GroupSpecifier = new GroupSpecifier("myGroup/g1");
groupspec.serverChannelEnabled = true;
groupspec.postingEnabled = true;
netGroup = new NetGroup(nc,groupspec.groupspecWithAuthorizations());
netGroup.addEventListener(NetStatusEvent.NET_STATUS,netStatus);
user = "user"+Math.round(Math.random()*10000);
}
GroupSpecifier
Řetězec definující skupinu. Každá skupina se liší nejenom jménem, ale i nastavením. Můžete nastavit následující vlastnosti:
- routingEnabled
- multicastEnabled
- objectReplicationEnabled
- peerToPeerDisabled – v případě multicastu definuje, že se má použít pouze Native IP Multicast například v nějaké interní síti, ne P2P Multicast či Fusion. Native IP Multicast ma tu výhodu, že nezobrazí dialog, kde musíte potvrdit, že se sdílením v rámci P2P souhlasíte. Stream do Native IP Multicast nelze poslat z Flash Playeru, ale pouze z Flash Media Serveru (budoucí verze). Funguje zde také LAN Discovery, Flash Player si najde nejbližší vhodné klienty a sníží tak latenci streamu.
- ipMulticastMemberUpdatesEnabled
- serverChannelEnabled
Nastavením těchto vlastností změníte specifikaci skupiny a jelikož je GroupSpecifier řetězec, změní se i tento řetězec, a vy se tak ocitnete v jiné skupině.
Krok 3: Zachycení stavových událostí
private function netStatus(event:NetStatusEvent):void{
trace(event.info.code);
switch(event.info.code){
case "NetConnection.Connect.Success":
// Uspesne jsme se pripojili k serveru
setupGroup();
break;
case "NetGroup.Connect.Success":
// Uspesne jsme se pripojili ke skupine
connected = true;
break;
case "NetGroup.Posting.Notify":
// Prisla nam zprava
receiveMessage(event.info.message);
break;
}
}
Krok 4: Odeslání zprávy
Vytvoříme objekt, do kterého zabalíme zprávu. Každá zpráva by měla mít nějaký unikátní identifikátor (sequence). Pokud odešleme stejnou zprávu bez unikátního identifikátoru, tak se podruhé nedoručí, všichni klienti už si totiž budou myslet, že tuto zprávu obdrželi – vzhledem k distribuci (přeposílání) v rámci P2P sítě je to logické.
var sequence:Number = 0;
private function sendMessage():void{
var message:Object = new Object();
message.sender = netGroup.convertPeerIDToGroupAddress(nc.nearID);
message.user = txtUser.text;
message.text = txtMessage.text;
sequence++
message.sequence = sequence;
netGroup.post(message);
receiveMessage(message);
txtMessage.text = "";
}
private function receiveMessage(message:Object):void{
write(message.user+": "+message.text);
}
private function write(txt:String):void{
txtHistory.text += txt+"\n";
}
Krok 5: Vytvoříme uživatelské rozhraní
<s:TextArea left="10" right="10" top="10" bottom="40" id="txtHistory"/>
<s:TextInput x="10" id="txtUser" text="{user}" bottom="10"/>
<s:TextInput left="145" right="88" id="txtMessage" bottom="10" enter="sendMessage()"/>
<s:Button label="Send" click="sendMessage()" enabled="{connected}" bottom="10" right="10"/>
Aplikace je tímto hotová, můžeme si ji vyzkoušet.
Bootstrapping
V kontextu P2P označuje zjednodušeně přidávání peerů do skupiny. Můžete jej provádět manuálně, anebo nastavit serverChannelEnabled na true a využít tzv. auto-bootstrapping, díky kterému se klienti do skupiny přidají automaticky.
Nic není tak růžové, jak se zdá
Ačkoliv je P2P velmi účinná technika, tak bohužel ne vždy funguje, protože může být blokována na firewallu. Hodně firem, zejména těch větších, blokuje UDP a nestandardní porty. Z mé vlastní zkušenosti zpravidla běžní uživatelé s ADSL či využívající kabelového připojení mají P2P povolené, zatímco zaměstnanci ve firmách blokované. Tenhle fakt je potřeba brát v úvahu a uvědomit si jej při rozhodování o tom, na koho je vaše aplikace zacílena. V každém případě je možné vytvořit aplikaci, která bude fungovat přes P2P, pokud to podmínky umožní – pokud ne, lze udělat failover přes RTMPT či HTTP s větší latencí. Budoucí verze Flash Media Serveru bude obsahovat API, které umožní Flash Media Serveru ovládat P2P skupiny a propojit tak oba světy – RTMP a RTMFP.
Poznámka: Diskutoval jsem s inženýry RTMFP, proč nelze vyřešit P2P ve Flashi tak, aby fungovalo i přes firewally – např. podobným způsobem jako funguje Skype – pomocí super-nodů. Odpověděli, že to lze, a dokonce je možné tento způsob přidat do Flash Playeru. Adobe se ovšem rozhodlo tento způsob zatím neimplementovat, protože nechce, aby se z Flash Playeru stal P2P software typu Torrent, který je ve spoustě firem zakázán z bezpečnostních důvodů. Adobe aktuálním přístupem dává provozovatelům sítě volbu – P2P protokol pro Flash povolit nebo zakázat na firewallu. Pokud si přejete explicitně povolit supernode P2P ve vašem Flash Playeru, můžete zeditovat mms.cfg a nastavit RTMFPTURNProxy. Viz diskuse zde. – pozn.aut.
Závěr
V článku jsme se seznámili se základy P2P technik ve Flashi, a to konkrétně ve verzi 10.1. (Pokud si chcete zkusit programovat P2P aplikace pro Flash Player 10, začněte tímto videotutoriálem). Pokročilejší věci, jako jsou multicast či zabezpečení, si necháme v případě zájmu na další díl.
Další zdroje
- Pokročilá přednáška o P2P, topologiích a RTMFP z MAXu 2009 od Matthewa Kaufmana (lead engineer RTMFP)
- Přednáška o nasazování P2P aplikací do sociálních sítí (Facebook) z MAXu 2009 – Tom Krcha
- Videotutoriál o základech P2P ve Flash Playeru 10
- Problematikou P2P se zabývá autor článku také na svém blogu FlashRealtime.com
