ugrás a tartalomhoz

WebSockets - oldalfrissítések lekezelése Firefoxban

haho · 2014. Jan. 6. (H), 16.24
Sziasztok! A kérdésemet specifikusan a Firefox böngészőhöz kapcsolnám, de valójában nem tudom, hogy Google Chrome-ban fenn áll-e ugyanaz a probléma, amire most a kérdésem vonatkozik, mert egyenlőre csak Firefoxban próbálkozom.

A kérdésem röviden:
hogyan a leghelyesebb lekezelni a websocketet kliens és szerver oldalon, ha a felhasználó lefrissíti a böngészőlapot?

A konkrét problémámat megpróbálom érthetően kifejteni:
1) Van USER1 és USER2, mindketten csatlakoznak egy WebSocket szerverhez (ami jelenleg PHP-ban van megírva).
2) Miután csatlakoztak felépítik egymást közt a peer-to-peer kapcsolatot és egy DataChannel-t, amely adatcsatornát egyszerű szöveges adatokat küldhetnek egymásnak.
3) Minden rendben van, a chat működik, MINDADDIG, amíg a szervert le nem állítom vagy amíg valamelyik felhasználó nem kéri a websocket bezárását. De ezen esetekben nincsen probléma, mert lefut a websocket onclose eseménye, és ezen esemény hatására küldök egy jelzést a szerverre, hogy "Zárd be az adott klienssel a kapcsolatot és vedd ki az adott kliens a socket felhasználókat tároló tömbből".
4) És itt jön a problémám: ha az egyik kliens lefrissíti vagy egyszerűen bezárja a böngészőlapot, akkor a websocket onclose esemény nem fut le. Ennek hatására nem küldődik el a szerver felé a jelzés, hogy záródjon be a kapcsolat és a szerveren lévő, a socket-okat tároló tömbből sem törlődik ki az adott kliens. Néhány másodpercnek el kell telnie, mire a böngésző (vagy a szerver??) felismeri, hogy van egy olyan kapcsolat, ami már használhatatlan.
Azért gondolom, hogy a böngésző ismeri ezt fel, mert az történik, hogy az oldalfrissítés után néhány másodperc múlva a szerver kap a bezárt klienstől egy 0 byte méretű adatcsomagot, melynek hatására a kapcsolat bezáródik (ha jól emlékszem a w3 specifikációban is olvastam, hogy üres adat esetén az a szabványos, ha zárjuk a kapcsolatot).
Mindezeknek (nem fut le a websocket onclose esemény és jó pár másodpercbe kerül a böngészőnek felismernie, hogy jelzést kell küldjön a szerver felé, hogy az zárja be a kapcsolatot az adott klienssel) eredményeképpen, ha pl. USER2 lefrissíti az oldalt, akkor az eredeti socket már nem lesz használható (igaz?, nem tudom eltárolni sehogy, nem?), ezért a JavaScript létrehoz egy új websocketot adott kliens és a szerver közt. Csakhogy EZUTÁN néhány másodperc múlva az előző (az oldal frissítés előtti) socket törlésre kerül a szerveren (mert eddigre jut el odáig a böngésző, hogy elküldje a 0 byte-os csomagot, hogy záródjon a kapcsolat). De emiatt automatikusan bezáródik a DataChannel kapcsolat és így a felhasználóknak újra kezdeményezniük kell egymás felé a kapcsolatot, stb.

Én azt elfogadnám, hogy oldal frissítés után megszűnik a kapcsolat és a felhasználók legyenek olyan értelmesek, hogy chat közben nem frissítik le az oldalt. De ez véletlenül is összejöhet nekik és a probléma tehát végeredményben az, hogy oldalfrissítés után még jó néhány másodpercet kell várni, mire a szerveren kiderül, hogy zárni kell a kapcsolatot és addig a felhasználóknak még ki sem tudom írni, hogy megszakadt a kapcsolat, mivel az kliens oldalon sem derül ki azonnal az oldal újratöltésekor (mint mondtam ez esetben a socket onclose eseménye nem fut le).

Mit tegyek tehát?
 
1

onunload

Hidvégi Gábor · 2014. Jan. 6. (H), 16.49
A window.onunload eseményben meghívhatnád a socket bezárását kézzel.
2

Eszembe jutott

haho · 2014. Jan. 6. (H), 17.49
Igen, nekem is eszembe jutott, kérdés, hogy vajon ez jó megoldásnak vagy fapados dolognak számít-e?
De jut eszembe mi történik, ha a felhasználó kihúzza a konnektorból a gépét. Akkor biztos nem fut le az onunload esemény.
Úgy érzem mintha több napnyi dokumentáció olvasgatás után leállt volna az agyam. Szóval lehet, hogy én bonyolítom túl.

Másnak van ötlete esetleg?
3

Azt hiszem leesett végre

haho · 2014. Jan. 6. (H), 18.14
Szóval vettem a fáradtságot és az elmélet helyett inkább végigpróbálgattam az előforduló eseteket és az ötleteimet.
Szóval a megoldást abban látom, hogy a WebSocket protokoll pont abban más, mint a HTTP, hogy képes más klienseknek is adatot küldeni, és nem csak annak, akitől a kérés érkezett a szerver felé. Hát ezt még meg kel szoknom...

A lényeg, hogy úgy csináltam, hogy ha bármelyik fél lefrissíti az oldalt/bezárja a böngészőt/kihúzza a gépét a konnektorból/bombát robbant a gépe mellett, akkor szerencsére a vele DataChannel kapcsolatot létesített klienseknél lefut a datachannel.onclose esemény. Ha pedig fut, akkor küldök egy olyan jelzést a szervernek, amire ő bezárja azt a websocket kapcsolatot, amelyik az ezen kérést a szervernek elküldő kliens DataChannel partnere volt.
így aki lefrissítette az oldalt ő látni fogja, hogy a felület leresetelődött és ezáltal látható lesz számára, hogy az adatkapcsolat megszűnt (pl. mert újra elérhető lesz a hívás kezdeményezése gomb), a másik félnek meg a datachannel.onclose eseménykezelő segítségével ki is írhatom, hogy megszűnt a kapcsolat és az ő oldalán is újra elérhetővé teszem a hívás kezdeményezése gombot.

Kipróbáltam működik. Ha pedig egy azon böngészőben nyitom meg a két klienst. És bezárom a teljes böngészőt, akkor meg a szerver azonnal érzékeli, hogy a két kliens nem elérhető és kitörli őket a felhasználók tömbjéből.
4

Jól értem, hogy akkor így

Ajnasz · 2014. Jan. 7. (K), 21.34
Jól értem, hogy akkor így bárki bannolhat bárkit? :)
5

Socket.IO t probaltad mar?

blacksonic · 2014. Jan. 9. (Cs), 13.55
Socket.IO t probaltad mar? igaz nem PHPs megoldas szerver oldalon de lekezel minden ilyen alacsony szintu problemat