WebSockets - oldalfrissítések lekezelése Firefoxban
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?
■ 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?
onunload
Eszembe jutott
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?
Azt hiszem leesett végre
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.
Jól értem, hogy akkor így
Socket.IO t probaltad mar?