Behöver råd kring client/server-modell

Diskussion i 'Frågor, support och diskussion' startad av uppdandom, 18 okt 2011.

  1. uncoloured

    uncoloured Teen Droid Medlem

    Blev medlem:
    21 feb 2010
    Inlägg:
    325
    Mottagna gillanden:
    16

    MINA ENHETER

    Hej guys,

    Börjar bli lite rörigt att läsa och sätta sig in i allt här, men du verkar ha ett bra flöde i ditt senaste inlägg uppdandom. Här är iaf mina two cents, hur JAG hade gjort det och inte nödvändigtvis "the right way"... ;) Ledsen om jag upprepar något.

    1. Glöm allt vad sockets heter för den här typen av server.
    2. I min mening, glöm prestandaproblem på webhotellet... Du kommer inte märka några problem om du inte har betydligt större behov av realtime data samt fler(?) samtidiga klienter. Kör man typ Loopia tycker jag man får rätt bra prestanda för PHP.
    3. VIKTIGT! Om du vill använda C2DM så börja med att läsa på om hur det fungerar, innan du skissar vidare på servern.

    Du behöver inte ha något script som ligger i någon "lyssnar-loop". Din app gör bara ett HTTP-anrop till ditt skript (example.com/makeMove.php) med all POST-data som behövs. När anropet sker så körs skriptet helt enkelt. Du uppdaterar databasen med aktuellt drag och skickar ett SUCCESS/FAIL till klienten.

    Hade du INTE använt C2DM så hade alla klienter gjort någon typ av long-poll ("Comet") till ditt skript för att se om det hänt något. Läs mer om Comet på wikipedia. Det innebär i princip att du gör ett traditionellt anrop för att hämta ny data, men om ditt skript inte hittar någon ny data så svarar det inte direkt. Istället går det in i en loop, väntar någon sekund och kollar efter ny data igen. Först när ny data hittas så avslutas skriptet/returnerar ett svar. Det innebär att från klientens håll ser det ut som att requesten laddar och laddar i all oändlighet, men så fort ny data hittas så är requesten färdigladdad med ny data. Lite illa beskrivet men hoppas du förstår principen. Det kan ju bli lite intensivt för databasen kan man ju tycka men allvarligt talat tror jag inte några requests per sekund är så mycket att tjafsa om för en okej databas. Sen kan man ju såklart bygga någon cache ovanpå men det ligger lite utanför detta forum tror jag.

    Å andra sidan så tänkte du nu använda C2DM och då blir det lite annorlunda. Som jag förstår det så bygger C2DM på att du registrerar ett konto hos Google som du sedan använder till din app. Du gör en HTTP request till Google som sen tar hand om att notifiera klienterna. Det vill säga, när en användare gör ett drag så skickas det till ditt serverskript, som uppdaterar databasen och skickar en request till Google, som i sin tur notifierar klienterna om att nu har något hänt så uppdatera spelplanen.

    Du behöver alltså bara ha två funktioner egentligen. En som tar hand om att uppdatera spelplanen med ett nytt drag, och en som listar hela spelplanen eller nya drag. Sen tar Google's C2DM hand om att notifiera klienterna om att en uppdatering har skett.
     
  2. uppdandom

    uppdandom Infant Droid Medlem

    Blev medlem:
    18 okt 2011
    Inlägg:
    10
    Mottagna gillanden:
    0

    MINA ENHETER

    Tack igen ReaPadda!

    Elegant lösning! Jag kommer inte att ha någon chat till att börja med, så jag stryker sockets till att börja med. En fråga: vilket webbhotell kör du på? Tillåter alla webbhotell användning av sockets (i t ex PHP)?

    Tack uncoloured för ett utförligt svar! Nu börjar det klarna ännu mer hur jag ska lägga upp det här!

    Fler samtidiga klienter kommer det ju definitivt att vara, men å andra sidan är kommunikationen så sparsam och sker så sällan att det nog inte är något problem.

    Loop/inte loop funderade jag på igår och drog just den slutsats du anger: det behövs ingen loop (till just detta i alla fall)

    Håller på att läsa på om C2DM just nu och ska försöka hitta PHP-kod för detta (det måste ju finnas färdig kod att använda för mina behov).

    Så här tänker jag mig flödet nu (från det att en användare startar klienten första gången)

    1. Klienten anropar C2DM och får ett RegistrationID.

    2. Klienten kontaktar servern (via ett registreringsscript) och skickar med detta RegistrationID (och t ex IMEI som ytterligare identifierare). Servern skapar en ny user i databastabellen USER och lägger in RegistrationID och IMEI i databasen. Ett user_id (som får vara unik nyckel) genereras och i svaret om att registreringen lyckats skickas detta user_id med (det används sedan vid varje anrop från klienten för att identifiera honom/henne).

    3. Vi tänker oss nu att det finns ett antal registrerade (och inloggade) klienter. En klient skickar en POST med en förfrågan om en ny spelomgång med vissa önskemål om spelinställningar. Denna förfrågan lagras i DB i en tabell GAME_REQUESTS.

    4. En annan klient skickar en POST med en spelomgångsförfrågan. Scriptet kollar i DB om det finns en matchande motståndare. Om det gör det skapas ett nytt spel i tabellen GAMES där inställningarna läggs in och båda USER läggs in. (Om det inte finns något spel uppstår en intressant situation som jag funderar över längre ner).

    5. Nu ska båda spelarna informeras om att ett spel har startats och få diverse parametrar. För den som skickade in den senaste POST:en räcker det väl att skicka ett svar? Varje http-request har väl automatiskt en response som kan skickas ut direkt? För den andra spelaren så behöver den notifieras via en C2DM-push. Nu hämtas den andra spelarens RegistrationID och en POST görs till C2DM-servern med kontonamn(emailID), autenticeringstoken, spelarens registration ID och meddelandet (typ "NEW_GAME_STARTED : GAME_ID 2567").

    6. Spelaren som pushats får ett meddelande om att det finns data att hämta och gör då en POST till servern för att hämta denna data som innehåller den info som behövs om spelomgången (som hämtas från GAMES-tabellen i DB).

    7. När spelet är igång agerar någon av spelarna. När denne väljer att göra sitt drag skickas info om draget till scriptet via en POST. Servern kollar upp draget och svarar med OK/NOT OK. Om det är OK läggs det in i databasen, spelbrädet (i en tabell BOARD) uppdateras och ett svar skickas till spelaren om att draget är ok. Den andre spelaren som också ska informeras kontaktas via C2DM om att det finns data att hämta. Denne gör då en POST för att hämta denna data. I svaret skickas den information som behövs med.

    8. På samma sätt fortsätter det tills spelomgången är slut. Då görs diverse uppstädning i DB och spelarna informeras om att spelet är slut (den ene via response och den andre via CD2M).

    Jag kommer att sätta mig ner och tänka igenom hur jag ska designa kommunikationsprotokollet (är lite sugen på JSON) och hur jag ska strukturera DB:en på bäst sätt.

    1. Ser logiken vettig ut? Tänker jag t ex rätt kring att det alltid finns en möjlighet att direkt skicka en response på POST och att den andre spelaren får en C2DM-push som gör att denne skickar en POST till servern.

    2. Jag undrar också litegrann kring det jag kommenterade i 4) ovan. Hur ska matchmakingen gå till? Det är ju enkelt om det finns en potentiell motståndare, men om det inte gör det när en spelares önskemål om ett spel kommer in? Här skulle jag väl behöva någon typ av matchmakingscript som loopar och försöker matcha spelare mot varandra?

    3. Hur försäkrar jag mig om att kommunikationen går fram åt båda håll? Klienten kan ju t ex kolla om nätverket är tillgängligt och inte skicka förrän det är tillgängligt. Därefter fortsätter den (i en tråd) att anropa tills den får ett svar. Hur ska servern veta att informationen nått fram? En liknande mekanism?

    Återigen tack för all hjälp!
     
  3. uncoloured

    uncoloured Teen Droid Medlem

    Blev medlem:
    21 feb 2010
    Inlägg:
    325
    Mottagna gillanden:
    16

    MINA ENHETER

    Klumpigt formulerat av mig, med "fler(?)" klienter menade jag "ett tusental klienter som KANSKE lyckas överbelasta servern" ;) Som du säger är detta inget du behöver tänka på just nu.

    Jag kan inte tänka mig annat än att de större webbhotellen har skalat rätt bra för olika typer av appar och flyttar/meddelar dig om det skulle bli några resursproblem. Vill inte göra någon reklam men personligen gillar jag Loopia, de känns seriösa och jag har kört lite olika typer av applikationer där utan problem.

    Sen ska du nog inte tänka dina klienter som "inloggade" för det är de "aldrig". Webbservern hanterar bara en request som kommer in, skickar ett svar och sen vilar den igen. Du bör hantera varje request från appen som ett fristående, dvs skicka med alla variabler och grejer du behöver för att identifiera och autentisera användaren varje gång.

    Tror inte det ska vara svårare än att du gör en vanlig HTTP request från PHP. Finns lite olika metoder att göra det på och här är det lite upp till webbhotellet och vilka funktioner som stöds.

    JSON låter bra! :) Hanterar du enkelt i både PHP och Java.

    Yep, se det som att du hämtar data från servern och på köpet kan du skicka med data när du gör det.

    Tycker du ska göra det mesta av felhanteringen i klienten. Vid matchmaking, skicka en förfrågan om det finns någon annan spelare som väntar. Gör det inte det så vänta lite och prova igen några gånger. Till slut kan du meddela spelaren om att det tyvärr inte finns någon tillgänglig motspelare. Samma sak vid annan kommunikation, jag skulle åtminstone inte inledningsvis brytt mig om att kolla nätverkstatus så mycket utan bara köra iväg ett anrop. Funkar det inte eller om du får ett oväntat svar, vänta lite och prova igen. Efter några gånger meddelar du att det blivit något fel och man kan försöka senare.

    Det finns lite olika inbyggda metoder för att sätta timeout, retries etc på anrop, använd dessa tillsammans med egna funktioner. Se bara till att alltid faila till slut och meddela användaren så de inte hamnar i någon tråkig evighetsloop.

    Sen tycker jag du ska titta lite på det omåttligt populära Wordfeud... känns som att de har tänkt på och implementerat det mesta av det du eftersträvar :) Där ser man t.ex. när man "kallstartar" appen att den inte är "inloggad", skärmen är tom någon sekund innan den hunnit snacka med servern och ladda ner aktuella spelomgångar.

    Lycka till!

    EDIT: Som jag misstänkte så använder Wordfeud C2DM för uppdateringar.
     
    Last edited: 21 okt 2011
  4. uppdandom

    uppdandom Infant Droid Medlem

    Blev medlem:
    18 okt 2011
    Inlägg:
    10
    Mottagna gillanden:
    0

    MINA ENHETER

    Har faktiskt redan reggat en domän och webbhotellplats där :)

    Låter som en väldigt bra plan. Jag gjorde nog det hela svårare än vad det behöver vara. Visst räcker det i majoriteten av fallen (samtliga fall där en användare agerar på ett eller annat sätt och klickar för att skicka iväg data)med några försök, felmeddelanden och timeouts, varefter användaren helt enkelt får försöka lite senare.

    Men ett undantag från detta måste väl dock vara efter att användaren tagit emot en push från servern? Det är ju inte användaren som är ansvarig för detta anrop utan servern. Och anropet betyder ju att det finns viktig data att hämta på servern. Här måste väl, som ReaPadda var inne på, användaren fortsätta anropa (while-loop med en try-catch-finally)tills han/hon får kontakt och tagit emot datan från servern?