SgtIgrams: JS Websocket verbindungsabbruch

Haiho!

nach langem tüfteln und nicht weiterwissen wollt ich mein problem mal mit euch teilen...

ich verbinde im browser ganz normal per websocket mit einem php server... handshake und alles funktioniert auch.. das problem tritt auch nur sporadisch auf.

es scheint meist nach dem senden der ersten 2-3 nachrichten an den server aufzutreten oder den antworten vom server. angekündigt wird das problem von einem gesendeten paket das ich unmaskiert als hex mit "03E9" darstellen kann oder noch maskiert mit "88806C24200B".. in seltenen fällen kommt auch das "03E9" in kombination mit etwas anderem und wird verbinden mit einem "+" oder einem "r"...

da ich im bereich websocket doch recht neu bin kann ich damit absolut nichts anfangen... könnte eine art End-of-file/stream benachrichtigung sein.. der client denkt jedenfalls der server hat die verbindung getrennt und der server denkt der client hat sie getrennt.. schieben sich also gegenseitig die schuld in die schuhe..

der websocket haut zudem ein fehler raus ohne daten... auch witzig..

merkwürdig ist vorallem da es nicht eindeutig reproduzierbar ist das es wirklich nur sporadisch auftaucht... aber wenn dann direkt zu beginn der verbindung

starten tu ich die verbindung mit:

new WebSocket(wsUri); 

und dann natürlich die entsprechenden callbacks auf onopen,onmessage,onerror und onclose

witzig zudem.. das socket.close() nicht immer funktioniert.. erst wenn ich die seite neu lade.. den tab komplett schließe.. oder sogar das fenster! beendet er sie komplett.. :(

die nachrichten werden alle im json format gesendet.. also nichts exotisches oder so... und am exakten inhalt der nachricht liegt es auch nicht... alles schon ausgeschlossen..

ich hoffe ich konnte mein problem ausreichend schildern und es gibt jemanden der mir helfen kann... danke im vorraus

grüße
-sgtigrams

  1. Moin!

    ich verbinde im browser ganz normal per websocket mit einem php server... handshake und alles funktioniert auch.. das problem tritt auch nur sporadisch auf.

    angekündigt wird das problem von einem gesendeten paket das ich unmaskiert als hex mit "03E9" darstellen kann oder noch maskiert mit "88806C24200B".. in seltenen fällen kommt auch das "03E9" in kombination mit etwas anderem und wird verbinden mit einem "+" oder einem "r"...

    ich hoffe ich konnte mein problem ausreichend schildern und es gibt jemanden der mir helfen kann...

    Einerseits lieferst Du recht genaue Informationen darüber, was für Bytes gesendet werden, andererseits fehlt jede Angabe zu:

    1. Browser
    2. Deinem Javascript (relevanter Code)
    3. eventuell verwendeten Webserver (PHP selbst bringt auch einen mit, der aber eher selten benutzt wird)
    4. PHP selbst (Version)
    5. dem PHP Skript (relevanter Code)

    Schau Dir hier mal die Antwort 20 an ("The thing of it is there are 2 main protocol versions of WebSockets in use today.") und überlege, ob Dein Problem damit zusammen hängen könnte.

    Jörg Reinholz

    1. Ahoi!

      vorkommen tut es bisher sowohl bei chrome als auch bei firefox... scheinbar unabhängig von der jeweiligen version. mit opera und dem guten altenhust...räusper.. verschluck internet explorer muss ich es noch ausprobieren...

      webserver benutze ich einen einfachen up-to-date apache... php "5.5.9-1ubuntu4.5"

      der js-code ist so ziemlich der aus vorzeigebeispielen einer ganz simplen verbindung.

      auf der php seite siehts etwa so aus:

              $_SERVER_SOCKET = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
              socket_set_option($_SERVER_SOCKET, SOL_SOCKET, SO_REUSEADDR, 1);
      
              socket_bind($_SERVER_SOCKET, 0, $port);
      
              socket_listen($_SERVER_SOCKET);
      

      zusätzlich zu den checks auf updates und co... wenn ich den ganzen sourcecode reinstellen würde hätte ich eine mordsarbeiten die sicherheitsrelevanten dinge rauszustreichen...

      was sich mir total entzieht das es mal vorkommt und mal nicht... es wirkt so als ob der browser eine statusmeldung sendet um den server eine schließende verbindung mitzuteilen.. aber selbst wenn dies der fall ist... warum schließt der browser sie einfach anstatt die nachricht zu senden die er soll???

      und da das try-catch einen error abfängt würd ich auch gern wissen wie ich aus den eventdaten irgendwas sinnvolles rausbekommen kann

      grüße

      • sgtigrams
      1. Moin!

        der js-code ist so ziemlich der aus vorzeigebeispielen einer ganz simplen verbindung.

        Der konkrete Code wäre aber dennoch interessant.

        1. Hier ein Beispiel aus dem Jahr 2010.
        2. Hier eines aus 2015.

        Du schreibst, Du öffnest die Verbindung mit

        new WebSocket(wsUri); 
        

        Wir können nur raten was passiert, weil wir Deinen Code nicht sehen. Möglicherweise ist es nämlich so, dass Du den Socket (etwa) so öffnest

        var exampleSocket = WebSocket(wsUri); 
        

        und aus irgendwelchen Gründen (welche nur aus Deinem Skript ersichtlich wären) passiert es, dass genau das nochmals aufgerufen wird:

        var exampleSocket = WebSocket(wsUri) // oder irgendwas anderes; 
        

        Wie würdest Du reagieren, wenn Du der Javascript-Interpreter wärst und man das Websocket-Objekt überschreibt?

        Wie schon geschrieben ist das alles Kristallkugelwissenschaft. Versuche uns zwei Beispielskripte aus deinem Code zu bauen (die das Verhalten aufweisen), damit wir uns das ansehen können. Wenn die Beispielskripte das Verhalten nicht aufweisen, dann liegt es womöglich an Deiner Programmlogik (wahrscheinlich die von Dir beschriebenen "sicherheitsrelevanten dinge" siehe oben).

        Jörg Reinholz

      2. Ahoi!

                $_SERVER_SOCKET = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
                socket_set_option($_SERVER_SOCKET, SOL_SOCKET, SO_REUSEADDR, 1);
        
                socket_bind($_SERVER_SOCKET, 0, $port);
        
                socket_listen($_SERVER_SOCKET);
        

        Ah, schön. Läuft das Ding da als richtiger Service (Daemon) oder hängt das einfach nur so scriptmäßig im Speicher rum? Das würde ich mir mal etwas näher anschauen, ggf. ne Logdatei schreiben. Wer weiß, wer den Prozess killt ;)

        Mfg

        1. "hängt" so im speicher rum :D

          im normalfall wird der serverstart per ajax in ner php schnittstelle gestartet. in debugfällen starte ich natürlich manuell einen über putty... beendet wird da garnichts... der server läuft munter weiter. auch alle anderen verbundenen clienten bleiben drauf. und da ich mir natürlich im log ausgeben lasse was der datenverkehr so ist sah ich ja überhaupt erst das jedesmal "03E9" bzw. 0x03 0xE9 gesendet wird und zack-boom connection weg. man kann danach auch mit dem selben browser wieder verbinden.

          was mir auch auffiel... firefox haut manchmal die fehlermeldung raus das "der websocket unterbrochen wurde während die seite geladen wurde" ... möglicherweise weil ajax zugriffe im hintergrund laufen... aber das wird wohl kaum ein problem sein oder doch? wär es möglich das javascript zu "beschäftigt" ist um die verbindung aufrecht zu erhalten?

          die ajaxzugriffe sind etwa alle 4 sekunden... also nichts übermäßiges

          da jetzt wochenende ist werd ich hoffentlich zeit finden das mal so herzurichten das ich das ich den quellcode posten kann... etwas leichter würde es mir natürlich fallen wenn es nicht zuu public ist und mich jemand in skype oder so "sgtigram" added.

          grüße

          • sgtigrams
          1. Ich habe jetzt auch mal einen Test gemacht: Baue ein Websocket zu einem ganz normalen Webserver auf. Der Webserver sendet die richtigen Header, das Handshake tut somit und die Verbindung wird hergestellt.

            Nun wäre ein Webserver kein Webserver wenn er die Verbindung nicht schließen würde. Genau das macht mein Webserver auch und was passiert: Der Client kriegt das gar nicht mit!

            Daher denke ich nun, dass Dein P. eher doch am Client liegt.

            PS: Den Socket-Server per ajax starten ist eine gute Idee. Wäre weiter ausbaufähig....

            1. Ich habe jetzt auch mal einen Test gemacht: Baue ein Websocket zu einem ganz normalen Webserver auf. Der Webserver sendet die richtigen Header, das Handshake tut somit und die Verbindung wird hergestellt.

              Um eine Websocketverbindung aufzubauen, musst du das Websocketprotokoll Server- und Clientseitig verwenden. Soweit ich weiß macht das kein "ganz normalen Webserver" einfach so. Clientseitig ist es im Browser implementiert. Serverseitig kenne ich es nur so, daß du dir eine Implementierung suchen musst.

              1. Ich habe jetzt auch mal einen Test gemacht: Baue ein Websocket zu einem ganz normalen Webserver auf. Der Webserver sendet die richtigen Header, das Handshake tut somit und die Verbindung wird hergestellt. Um eine Websocketverbindung aufzubauen, musst du das Websocketprotokoll Server- und Clientseitig verwenden. Soweit ich weiß macht das kein "ganz normalen Webserver" einfach so.

                Der macht das schon, wnn er entsprechend angewiesen wird, sendet er auch die richtigen header. Noch besser ist die "non parsed header" -Technik, da reicht der Webserver die header nur durch.

                Aber insgesamt taugt sowas nur zum Testen ob der Client überhaupt eine Verbindung aufbauen kann.

                mfg

                1. Der macht das schon, wnn er entsprechend angewiesen wird, sendet er auch die richtigen header.

                  Die sendet er aber nicht einfach so.

                  Noch besser ist die "non parsed header" -Technik, da reicht der Webserver die header nur durch.

                  Vom Serverscript, das muß aber erst mal die Header erzeugen.

                  1. Zum Verständnis: Normalerweise werden die header geparsed. D.h.: Vom script her steht z.B.

                    header( Connection => 'Upgrade' );
                    

                    was der Webserver bekommt. Der Webserver parst ALLE vom Script gesendeten header und je nach Konfiguration werden die ggf. vom Webserver ergänzt. Beispielweise ergibst sich dann für einen Response-Header "Connection":

                    Connection: Upgrade, Keep-Alive
                    

                    NPH nun, ist eine Technik, womit das Parsen unterdrückt wird. Ein NPH-Script ist voll verantwortlich dafür, dass ALLE erforderlichen Response-Header rausgehen und letztendlich gehen auch nur diejeniger header raus, welche in einem NPH Script notiert sind. Wenn da steht

                    header( Connection => 'Upgrade' );
                    

                    sendet der Webserver auch nichts anderes als

                    Connection: Upgrade
                    

                    Er ist sozusagen transparent und auf diese Art und Weise kannst Du die Herstellung einer Websocket Verbindung emulieren.

                    1. auf diese Art und Weise kannst Du die Herstellung einer Websocket Verbindung emulieren.

                      Das musst du aber alles selbst machen. Womit wir wieder bei meiner Ursprungsaussage wären, kein "ganz normalen Webserver" macht das einfach so. Weder sendet er die richtigen Header, noch funktioniert damit das Handshake.

                      1. auf diese Art und Weise kannst Du die Herstellung einer Websocket Verbindung emulieren. Das musst du aber alles selbst machen. Womit wir wieder bei meiner Ursprungsaussage wären, kein "ganz normalen Webserver" macht das einfach so. Weder sendet er die richtigen Header, noch funktioniert damit das Handshake.

                        Das Herstellen der Verbindung (nur das Handshake!) ist native HTTP. Ausschlaggebend ist der Vom WS Client gesendete HTTP_SEC_WEBSOCKET_KEY und alles Weitere ist nur ein bischen Tipparbeit. Wie die Response.Header auszusehen haben und wie sie erzeugt werden, findest Du mit jeder Suchmaschine.

                        mfg