Ankündigung

Einklappen
Keine Ankündigung bisher.

PHP-Websocket-Lösungen oder Alternativen

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • PHP-Websocket-Lösungen oder Alternativen

    Hallo zusammen,

    für ein Hobby-Projekt habe ich mich mal (wieder) mit Websockets beschäftigt. Ich hatte schon mal früher ein Projekt mit einer Bastellösung und wollte jetzt eine PHP-Bibliothek dafür verwenden.
    Das Aktuellste, was ich finde ist Ratchet:
    https://github.com/ratchetphp/Ratchet
    Das wurde aber 4 Jahre nicht angefasst.
    Kennt jemand Alternativen, die aktueller sind?

    https://github.com/facundofarias/awe...me-ov-file#php
    brachte auch nicht mehr.

    Die Frage ist, ob der Websocket-Server unbedingt in PHP geschrieben sein muss, oder ob es eigentlich relativ egal ist, was man nimmt. Hauuptsache von PHP aus ansprechbar und gut gepflegt.

    Dann habe ich mir auch angesehen, was es für Websocket-Alternativen gibt:
    https://ably.com/topic/websocket-alternatives

    Interessant fand ich SSE (Server-Sent Events)
    https://github.com/mdn/dom-examples/...events/sse.php

    Eventuell reicht das schon für meine Zwecke. Es bleibt aber für mich die Frage, warum PHP keine aktuellen Websocket-Lösungen mehr hat. (Oder ich finde sie nicht.)
    Oder macht man doch lieber alles mit Fetch API im Sekundentakt?

    Ich freue mich auf eure Antworten.

    Viele Grüße

    Peter

  • #2
    Swoole kann Websocket.

    Zu beachten ist dabei, dass die Erweiterung nicht klassisch mit einem Webserver wie Apache oder Nginx läuft, sondern als (endloses) shellscript, dass seinen eigenen Serverprozess bereitstellt.

    Es gibt auch ein ziemlich gutes Framework namens hyperf
    Die Basisdoku gibt es in englisch, die meisten Diskussionen dazu sind allerdings chinesisch. Lässt sich aber bei Bedarf auch gut googletranslaten.

    GitHub - hyperf/hyperf: ? A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease.

    Es ist im ersten Moment etwas ungewohnt, wenn man mit ständig laufenden Serverprozessen keine Erfahrungen hat, aber es ist wirklich sauschnell und gut aufgebaut.

    Kommentar


    • #3
      Zitat von reddighamburg Beitrag anzeigen
      Swoole kann Websocket.
      [...]
      Es gibt auch ein ziemlich gutes Framework namens hyperf
      Vielen Dank für die Tipps. Ich werde mir das mal ansehen.

      Als Antwort auf die Frage, warum es keine aktuellen Websocketlösungen zu geben scheint, könnte man also antworten: Die stecken in aktuellen Frameworks mit drin. Daher erübrigen sich Einzellösungen wir Ratchet und Wrench.

      Gefunden habe ich noch Reverb für Laravel : https://reverb.laravel.com/

      Die Anleitung für meine damalige Lösung hatte ich hier gefunden:
      https://phppot.com/php/simple-php-chat-using-websocket/
      Das war mir eigentlich sympatisch, weil man noch nachvollziehen kann, was da abläuft.

      Die Frage ist, wie groß ich das aufziehen will. Wie gesagt, es geht um ein Hobby-Projekt, eher für den Familieneinsatz gedacht: ein Kniffelspiel mit Sonderregeln, das netzwerkfähig sein soll. Ich mache dafür in den näcsten Tagen mal ein neues Thema auf, vielleicht bekomme ich ja noch ein paar Tipps.

      Kommentar


      • #4
        Das "Problem" mit php und websocket ist immer das gleiche. Websocket benötigt eine dauerhafte Verbindung. Das widerspricht dem klassischen Ansatz von php (request -> response -> fertig)

        Daher müssen alle php Implementierungen auf einen ständig laufenden Serverprozess zurückgreifen. Das ist zwingend notwendig, weil sonst ja am ende des Script auch das socket geschlossen werden würde.

        Viele Lösungen bedienen sich dabei pthreads oder ähnlichem, und fallen nach dem erfolgreichen Handshake dann in den endlos Loop für das Socket.
        Das funktioniert, aber ist wenig flexibel.

        Swoole / hyperf verfolgt stattdessen so ein wenig das node.js Modell. Das php-script IST der Server. Dadurch werden Sockets, Hintergrund-Prozesse und Events möglich. Gleichzeitig tötet das aber die Sessions, weil es keinen getrennten User-Kontext mehr gibt, sondern alle Anfragen in denselben Prozess rein laufen. Man muss sich also seines eigenen Session Handler bedienen, da man in der Hauseigenen $_SESSION superglobalen die Daten verschiedener User vermischen würde (weil es eben davon nur eine gibt, und nicht jeder seine eigene hat).

        Nichts desto trotz hab ich auch bei kleinen Projekten bisher mit hyperf sehr gute Erfahrungen gemacht.

        Alternativ kann man auch neben dem websocket prozess einen klassischen webserver laufen lassen, benötigt dann aber methoden zum Datenaustausch zwischen den beiden (http und ws) services. Ein Redis oder ne queue (mqtt, amqp) kommen in Frage... Ist aber eleganter, das gleich alles in einem Guss zu machen, und da kann ich hyperf mit swoole wirklich sehr empfehlen.
        ​​​

        Kommentar


        • #5
          Zitat von reddighamburg Beitrag anzeigen
          Swoole / hyperf verfolgt stattdessen so ein wenig das node.js Modell. Das php-script IST der Server. Dadurch werden Sockets, Hintergrund-Prozesse und Events möglich.
          ​​​
          Danke für die interessanten Erläuterungen. Da hätte ich gleich Lust, mich damit zu beschäftigen.
          Jetzt aber mal praktisch gesehen: So ein Projekt lässt sich doch wohl nicht mit einem Standard-Hosting-Paket erledigen. SSE wäre da weniger anspruchsvoll.

          Es geht um die Umsetzung dieses Würfelspiels. (Der Name Kniffel ist rechtlich geschützt, das Spiel selbst aber wohl nicht, denn es gibt zahlreiche Anbieter für die Würfelblöcke mit gleichen Regeln und anderen Namen)
          https://onlinespiele.schmidtspiele.de/?/home
          Hier sieht man schon, wie es in etwa aussehen könnte.:

          Hintergründe hier:
          https://de.wikipedia.org/wiki/Kniffel

          Die Sonderregel ist, dass man immer gleichzeitig drei Spalten füllt statt nur einer und zwar mit einfacher, doppelter und dreifacher Wertung.
          Das macht die Sache interessanter aber komplizierter, ist aber für die Umsetzung nicht weiter entscheidend.

          Natürlich soll man gegen den Computer (bzw. die KI) spielen können und es sollen mehre Spieler gegeneinander antreten können.

          Das wäre es im Groben. Die Daten selbst sind also eher klein. Das Refresh-Intervall könnte man auf 5 Sekunden setzen, ohne dass man eine Verzögerung merken sollte. - Ist da nicht hyperf eine Nummer zu groß?

          Man könnte alle Spielzüge durchnummerieren und in eine Datei schreiben (ähnlich wie bei einer Schachnotation) und dann dem Client bei entsprechenden Events (neue Einträge) die aktuellen Daten senden. (Oder der Cleint fragt regelmäßig ab, obe es etwas neues gibt.

          Wie würde ein Spieleentwickler das lösen?

          Kommentar


          • #6
            Das würde ich von der zu erwartenden Last abhängig machen.

            Richtig ist, dass Standard-Hosting ungeeignet ist, weil man dort auf die laufenden Server, also idR Apache oder nginx angewiesen ist und keinen eigenen Prozess zum laufen bekommt.

            Ein kleiner VPS sollte aber durchaus genügen und kostet auch nicht die Welt. Natürlich hast du dich da um Sicherheitsupdates des Betriebssystems dann selbst zu kümmern.

            Ein regelmäßiges Pollen (Nachfragen, ob es etwas neues gibt) ist grundsätzlich völlig in Ordnung, aber je nach Frequenz wird eben bei vielen Anfragen die Antwort einfach "nein" sein, und die Anfrage selbst war im Nachhinein betrachtet überflüssig.

            So ein Würfelspiel isr da allerdings noch recht überschaubar.
            Trotzdem wird es im echten PvP immer eine Zeit brauchen, bis der Gegner seinen Zug macht, und es laufen in der Zeit Anfragen ins leere.

            Tatsächlich betreuue ich für einen Kunden zwei Strategiespiele älteren Jahrgangs, die genau das tun (alle paar Sekunden nachfragen).
            Es ist lasttechnisch schon bei wenigen hundert Spielern eine Vollkatastrophe und ich würde es bei PvP Spielen so niemals machen.
            Bei PvE spielen ist es vertretbar, weil der Server einfach schneller spielt und mit beinahe Sicherheit immer ein neues Ergebnis liefern kann.

            Spieler gegen Spieler ist allerdings immer eine bidirektionale Verbindung vorzuziehen, wo der Server bescheid sagen kann, wenn es etwas gibt.

            Eventuell möchtest du dein Spiel auch auf Mobilgeräten ordentlich spielbar haben. Hier hast du sogar noch ein größeres Problem, weil eine mobile Internetverbindung weniger schnell und dazu noch weniger stabil ist. Trotzdem soll ein Spiel ja nicht abreißen. Der Server sollte hier in der Lage sein, festzustellen ob ein Spieler "weg" ist, oder gerade nur Kaffee holt. Das geht bei einer stateless Verbindung mit reinem http nicht, weil der Server keine Möglichkeit hat, von sich aus den Client abzufragen. Natürlich kann man auf den nächsten "ping" vom client warten, aber so wirklich das gelbe vom Ei ist das nicht.

            Ein regelmäßiges pollen nach Änderungen ist möglich und ein durchaus valider Ansatz. So wurde es vor der Erfindung von Websocket immer gemacht.
            Websocket ist näher an Echtzeit und verzichtet auf unnötige Anfragen, benötigt aber eine stabilere Verbindung und ist mit Standard-Hosting meistens nicht möglich. Ein kleiner VPS ist aber auch nicht teuer. Ich kann dir per PN einen Anbieter empfehlen, den ich seit Jahren für meine Server nutze, wenn du möchtest.
            ​​​​​​

            ​​​​​

            ​​​​​

            ​​

            Kommentar


            • #7
              Danke für das Angebot. Ich habe gesehen, dass mein eigener Account doch einiges mehr hat, als ich erwartet habe. (SSH und Möglichkeiten zur Installation per Composer) Das werde ich zunächst mal testen und habe da auch Support. Erst mal mache ich das aber lokal. Das wäre dann auch gleich eine Gelegenheit, mich intensiver mit Docker zu beschäftigen.

              Ich habe mir jetzt auch die SSE (Server-Site Events) noch mal genauer angesehen.
              https://github.com/mdn/dom-examples/...er-sent-events
              Das schließt eigentlich die Lücke zwischen Polling und Websockets.

              Für jeden Client wird (offenbar) ein eigener Prozess mit einem Loop gestartet. (Vielleicht würde das auch dein Problem mit den Altprogrammen lösen, sofern das nötig ist.) Das "Polling" findet damit auf dem Server statt, und der Client wird nur per Push informiert, wenn es etwas gibt.

              Wenn ich eine UID anhänge,
              Code:
               const evtSource = new EventSource('sse.php?uid=7');
              Kann ich per $_GET['uid'] den einzelnen Clients individuelle Nachrichten schicken.

              Das Spiel soll - wie gesagt - privat genutzt werden. (Familiengröße). Eine einfache Lösung könnte man zum Download anbieten, und würde vermutlich mehr Interessenten ansprechen als ein großes komplexes System, für das man einen Administrator braucht.

              Kommentar


              • #8
                Das ist im Prinzip eine Seite, die unendlich "lädt" und Stück für Stück neue Inhalte schreibt. Das kann man ganz grob mit einem gestreamten Video vergleichen.
                Das kann funktionieren, solange die Menge der Daten überschaubar bleibt, denn aus sicht des client lädst du eine große Datei von einem "sehr langsamen" Server.
                Der Browser wird also alte Daten von sich aus nicht aufräumen, bis die Sitzung beendet wird.

                Außerdem benötigst du Clientseitig natürlich Methoden, die jeweils neuen Daten auszuwerten, und das bevor die Datei "fertig" geladen ist (denn das ist sie nie).

                Kommentar


                • #9
                  Die Sitzung kann der Client mit Javscript beenden.
                  Code:
                  evtSource.close();
                  Außerdem muss die Datei nicht groß sein.
                  Nehmen wir mal eine Schachpartie, die sich über drei Stunden hinzieht.

                  Hier ist ein Stück aus einer Notation im pgn-Format

                  Code:
                  1. e4 e5 2. Nf3 Nf6 3. Nxe5 d6 4. Nf3 Nxe4 5. d4 d5 6. Bd3
                  Bd6 7. O-O O-O 8. c4 c6 9. Qc2 Na6 10. a3 Bg4 11. Ne5 Bxe5
                  12. dxe5 Nac5 13. f3 Nxd3 14. Qxd3 Nc5  usw. ...
                  (Bei Zug 30 oder vorher könnte schon Schluss sein.)

                  Auf dem Server kann in der Schleife alle 15 Sekunden aus einer Quelle abgefragt werden, ob ein neuer Zug gemacht wurde. (Bzw. mehrere seit der letzen Abfrage). Die neuen Daten werden dann gesendet oder die Schleife läuft ohne Aktion in die nächste Runde.

                  Clientseitig wird dann auf das Event gelauscht.

                  Code:
                  evtSource.onmessage = function(e) {
                  Die neuen Züge werden dann grafisch dargestellt.

                  Das ist das gleiche wie bei einer Websocket-Verbindung, nur dass der Client keinen Rückkanal hat. Den kann er aber über Ajax aufmachen.

                  Serverseitig könnte auch eine Socketverbindung zu dem Script mit dem Loop vorhanden sein, so dass das SSE-Script nicht selbst abfragen muss. (Das habe ich aber noch nicht getestet.)
                  Dann würde man aber vielleicht gleich einen Websocket-Server nehmen.


                  Kommentar


                  • #10
                    Auf dem Server kann in der Schleife alle 15 Sekunden
                    Ich wär da eher bei 15x pro Sekunde oder so
                    Wenn du die Züge in einer schnellen Quelle speicherst (und ggf. nur periodisch in einer DB persistierst), frisst das kein Brot.

                    Bei 15 Sekunden wärst du sogar langsamer, als die zuerst überlegten 5-Sekunden clientseitiges pollen. Das willst du nicht. 15 Sekunden können sich seeehr lange anfühlen.

                    Ideal wäre eine beliebige queue (RabbitMQ o.ä) oder eine Schnelle Memory DB (Redis? memcacheD?) oder falls bei dir nicht möglich ggf. sogar ein einfacher Filestream oder shared memory block.

                    Du benötigst ja eine Möglichkeit, die Züge von Spieler A an den Prozess von Spieler B zu übertragen, und umgekehrt.
                    Das geht auch über ne mySQL, ist aber dann ein ganz schönes Gehämmer gegen die Instanz. Die sollte das zwar bequem vertragen, insbesondere wenn es eben meistens nichts neues gibt, aber dann würde ich wenigstens auch hier temp tables in memory verwenden.


                    ​​​
                    ​​​​​

                    Kommentar


                    • #11
                      Die 15 Sekunden waren als vereinfachendes Beispiel für eine Schachpartie gerechnet. Bei dem geplanten Würfelspiel hätte man vielleicht vier Spieler. Es gibt die Aktionen:
                      1. Wurf |1- 5 Wüfel urücklegen| 2. Wurf (optional) | Zurücklegen (optional) |3. Wurf optional | Eins der erlaubten Felder auswählen und Ergebnis eintragen
                      Dann kommt der nächste Spieler an die Reihe. Das dauert schon ein paar Sekunden pro Spielzug. In der Darstellung am anderen Bildschirm muss man nicht unbedingt die Pausen und Wartezeiten eins zu eins abbilden. Wenn man für das Würfeln nur 3 Sekunden braucht und für das Eintragen mit Überlegung 10 Sekunden, kommt man insgesamt wieder hin. Die Würfelanimation kann man ja auch noch etwas in die Länge ziehen.

                      Ansonsten vielen Dank für deine Tipps, auch bezüglich Redis etc.. (Habe ich mir mal lokal installiert und werden damit experimentieren.) Ich melde mich wieder, wenn ich ein Stück weiter bin.

                      Kommentar

                      Lädt...
                      X