Ankündigung

Einklappen
Keine Ankündigung bisher.

Problem mit fsockopen und fgets

Einklappen

Neue Werbung 2019

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

  • Problem mit fsockopen und fgets

    Hi,

    ich habe das folgende Problem:
    zur Zeit schreibe ich an einer Server-Client Anwendung.
    Den Server schreibe ich in c#, was ganz gut geht.
    Ich kann auch schon mit dem php Client auf den Server verbinden und wenn ich etwas in den Stream schreibe kann der Server das auch wieder lesen.
    So weit so gut.
    Da ich aber mit dem Client nicht nur Daten senden will, sondern das ganze mit Anfrage/Antwort lösen will, muss ich danach auch wieder Daten aus dem Stream lesen.
    Und das ist mein Problem, irgendwie scheint Php das Ende des Streams nicht zu erkennen :S.

    PHP-Code:
    <?php
    function connect() {
      echo 
    "connecting...\n";
      
    $sock =  fsockopen("127.0.0.1"10000);
      return 
    $sock;
    }

    function 
    send($fp$bytes) {
      echo 
    "sending data...\n";
      
    fputs($fp$bytes);
    }

    function 
    receive($fp) {
      echo 
    "receive data...\n";
      
    $response "";
      
    //socket_set_blocking($fp, false);
      
    $response fgets($fp256);
      return 
    $response;
    }

    $request = array("Request" => "GetStatus");
    $sock connect();
    $response request ($sock$request);
    echo 
    $response."\n";
    ?>
    Wenn ich blocking aktiviere, dann bleibt er beim empfangen der Daten hängen, deaktiviere ich es, dann geht er einfach darüber hinweg ohne etwas zu lesen.
    Wenn ich weniger Daten lese als im Stream sind, dann funktioniert es jedoch problemlos, setze ich einen höheren Wert als die Länge des Streams, dann passiert was ich oben schon beschrieben habe.
    Hoffe ihr könnt mir hierbei helfen

    Gruß Flo

  • #2
    Du könntest mal stream_get_contents() statt fgets() testen.

    Kommentar


    • #3
      Du könntest mal stream_get_contents() statt fgets() testen.
      hat leider nichts gebracht...

      Ich glaube langsam es liegt an meinem Server Code.
      Kann ich einfach so in den Stream schreiben und mit dem Client das ganze wieder auslesen?

      Das ist mein Server Code zum Senden des "Responses":
      Code:
      public void send(string str)
      {
          // write response ...
          byte[] data = Encoding.ASCII.GetBytes(str);
          this.cstream.Write(data, 0, data.Length);
      }
      (dürfte denke ich auch für phpler zu verstehen sein :P )
      Wenn ich nach dem Senden der Antwort die Verbindung schließe, dann klappt es und der Client liest die Daten aus dem Stream.
      Allerdings möchte ich die Verbindung beibehalten, da sich der Client zuerst bei dem Server authentifizieren sollte und ich nicht Login und Passwort bei jeder Anfrage erneut senden will...

      Kommentar


      • #4
        Zitat von FloMX
        Du könntest mal stream_get_contents() statt fgets() testen.
        hat leider nichts gebracht...
        http://de3.php.net/manual/en/function.fread.php
        fread() reads up to length bytes from the file pointer referenced by handle.
        Reading stops [...] (for network streams) when a packet becomes available.

        Kommentar


        • #5
          Zitat von karl-150
          Zitat von FloMX
          Du könntest mal stream_get_contents() statt fgets() testen.
          hat leider nichts gebracht...
          http://de3.php.net/manual/en/function.fread.php
          fread() reads up to length bytes from the file pointer referenced by handle.
          Reading stops [...] (for network streams) when a packet becomes available.
          Ah, danke, da liegt der Hase im Pfeffer
          Hat jemand eine Ahnung wie man das Lösen könnte?
          Die Ansätze auf der Seite funktionieren nicht..
          habe auch schon sämtliche sock_x() funktionen ausprobiert, langsam weicht meine Hoffnung dem Verzweifeln...

          Kommentar


          • #6
            Zitat von FloMX
            Hat jemand eine Ahnung wie man das Lösen könnte?
            Reading stops [...] (for network streams) when a packet becomes available.
            Genau das sollte doch zutreffen, wenn Du Daten mit fgets() etc. einlesen
            kannst. Nur das diese Funktion erst beim Erreichen des Datei- bzw.
            Zeilenendes "aufgibt". Wenn Du die Verbindung aufrecht erhälst, sollte
            das also so nichts werden.

            Ein einfaches fread($fp, 4711) hingegen sollte es meiner Meinung nach tun.

            Wie sieht denn genau Dein Skript / Ansatz aus, der hier gescheitert ist?

            Kommentar


            • #7
              Das Problem liegt darin das der String im C Programm mit einer binären Null terminiert wird ... PHP bzw. die Funktion fread kennt keine binäre Null als Stringende sondern nur den Zeilenumbruch ... du must dem String vor der binären Null praktisch noch einen Zeilenumbruch "\n" mitgeben dann sollte es funktionieren.

              Kommentar


              • #8
                Danke erstmal für die Vorschläge, ich kann mir auch gut Vorstellen, dass das mit dem "\n" in die richtige Richtung geht, allerdings ist immer noch irgendetwas verkehrt :S.
                Möglicherweise könnte der Fehler darin liegen, dass Encoding.ASCII.GetBytes(str + "\n"); das \n einzeln übersetzt (\ und n)?
                Edit: nein, habs geprüft, das \n wird als zeichenumbruch übertragen...

                hier ist mein Ansatz.
                Client Code zu Empfang der Daten:
                PHP-Code:
                <?php
                function receive($fp) {
                  while (!
                feof($fp)) {
                    
                $data .= fread($fp128);
                  }
                  return 
                $data;
                }
                ?>
                Server Code zum Senden der Daten:
                Code:
                public void send(string str)
                {
                    // write response ...
                    byte[] data = Encoding.ASCII.GetBytes(str + "\n");
                    this.cstream.Write(data, 0, data.Length);
                    this.cstream.Flush();
                }

                Kommentar


                • #9
                  Zitat von HStev
                  Das Problem liegt darin das der String im C Programm mit einer binären Null terminiert wird ...
                  Schön, dass dem in C so ist. Hier aber nicht von Interesse.

                  Zitat von HStev
                  PHP bzw. die Funktion fread kennt keine binäre Null als Stringende sondern nur den Zeilenumbruch ...
                  In PHP arbeitet man also mit "zeilenumbruchterminierten" Strings? Interessant...


                  Zitat von FloMX
                  while (!feof($fp)) {
                  feof() ist hier die falsche Lösung, da diese Funktion erst beim Timeout des
                  Sockets greift.

                  Zitat von [url
                  http://de2.php.net/feof[/url]]Returns TRUE if the file pointer is at EOF or an error occurs (including
                  socket timeout
                  ); otherwise returns FALSE.
                  Wenn Dir mein obiger Vorschlag nicht gefällt / wieso auch immer nicht
                  funktionieren sollte, kann Dir eventuell socket_select() in Verbindung
                  mit socket_set_timeout() weiterhelfen.

                  http://php.net/socket_select
                  http://php.net/socket_set_timeout

                  Kommentar


                  • #10
                    Schön, dass das in C so läuft. Hier aber nicht von Interesse.
                    Dein Kommentar ist auch nicht von Interesse.

                    Wenn Dir mein obiger Vorschlag nicht gefällt / wieso auch immer nicht
                    funktionieren sollte, kann Dir eventuell socket_select() in Verbindung
                    mit socket_set_timeout() weiterhelfen.
                    Mit socket_set_timeout() wäre es mit Sicherheit möglich, allerdings finde ich die Lösung etwas zu unsicher...

                    Ich hab es gerade geschafft eine Lösung zu finden, juhu

                    Senden der Daten:
                    Code:
                    public void send(string str)
                    {
                        // write response ...
                        byte[] data = Encoding.ASCII.GetBytes(str + "\r\n");
                        this.cstream.Write(data, 0, data.Length);
                        this.cstream.Flush();
                    }
                    Empfang der Daten:
                    Code:
                    <?php
                    function receive($fp) {
                      while(substr($data, strlen($data) - 2) != "\r\n") {
                        $data .= fread($fp, 1024);
                      }
                      return $data;
                    }
                    ?>
                    (der bb php tag ist irgendwie kaputt :S)

                    Kommentar


                    • #11
                      Zitat von karl-150
                      Zitat von HStev
                      Das Problem liegt darin das der String im C Programm mit einer binären Null terminiert wird ...
                      Schön, dass dem in C so ist. Hier aber nicht von Interesse.
                      hmm irgendwie sind hier im PHP.de Forum immer so provokativ sorry aber das scheint echt ne Angewohnheit von PHP Codern zu sein

                      Zitat von karl-150
                      Zitat von HStev
                      PHP bzw. die Funktion fread kennt keine binäre Null als Stringende sondern nur den Zeilenumbruch ...
                      In PHP arbeitet man also mit "zeilenumbruchterminierten" Strings? Interessant...

                      Zitat von FloMX
                      while (!feof($fp)) {
                      feof() ist hier die falsche Lösung, da diese Funktion erst beim Timeout des
                      Sockets greift.
                      falsch, feof müsste hier nämlich genau beim Zeilenumbruch greifen alles was danach kommt gehört zum nächsten Packet

                      Zitat von karl-150
                      Zitat von [url
                      http://de2.php.net/feof[/url]]Returns TRUE if the file pointer is at EOF or an error occurs (including
                      socket timeout
                      ); otherwise returns FALSE.
                      Wenn Dir mein obiger Vorschlag nicht gefällt / wieso auch immer nicht
                      funktionieren sollte, kann Dir eventuell socket_select() in Verbindung
                      mit socket_set_timeout() weiterhelfen.

                      http://php.net/socket_select
                      http://php.net/socket_set_timeout
                      noch schlimmer willst bei jeden Packet auf das Socket Timeout warten? So langsam fang ich an zu verstehen warum einige Netzwerkprogramme so lahm sind...

                      Kommentar


                      • #12
                        Zitat von HStev
                        hmm irgendwie sind hier im PHP.de Forum immer so provokativ
                        Stimmt. Den Satz hätte ich mir sparen können. Sorry.

                        Zitat von HStev
                        falsch, feof müsste hier nämlich genau beim Zeilenumbruch greifen alles was danach kommt gehört zum nächsten Packet
                        feof() liefert Dir beim Socket-Timeout TRUE zurück, nicht nach Empfang
                        eines Datenpakets.

                        Abgesehen davon, bringt Dir auch die Prüfung auf CRLF nichts, da ein
                        Paket zum einen nicht dadurch beendet wird und Du zum anderen von
                        der Trennung der Pakete in den von fread() etc. eingelesenen Daten
                        überhaupt nichts mitbekommst.

                        Zitat von HStev
                        noch schlimmer willst bei jeden Packet auf das Socket Timeout warten? So langsam fang ich an zu verstehen warum einige Netzwerkprogramme so lahm sind...
                        Natürlich sollte man den Timeout möglichst niedrig setzen bzw. direkt in
                        den non-blocking-Modus schalten, wenn die Daten sofort verfügbar sind.

                        Kommentar


                        • #13
                          Zitat von karl-150
                          Abgesehen davon, bringt Dir auch die Prüfung auf CRLF nichts, da ein
                          Paket zum einen nicht dadurch beendet wird und Du zum anderen von
                          der Trennung der Pakete in den von fread() etc. eingelesenen Daten
                          überhaupt nichts mitbekommst.
                          das dachte ich mir bis zu einen merkwürdigen erlebnis auch, kleiner selbst geschriebener Server und die Daten per PHP ausgelesen ... das Script hat sich immer aufgehangen bis ich dann auf Server Seite das CRLF eingefügt hatte und schon lief das ganze Reibungslos.

                          ok ich seh grad da hab ich allerdings mit
                          Code:
                          $data = fgets($this->socket, 128);
                          gearbeitet aber das hat funktioniert

                          string fgets ( resource handle [, int length] )

                          Gibt eine Zeile bis zu length -1 Bytes Länge zurück, welche aus der Datei von der aktuellen Position des Dateizeigers handle aus ausgelesen wird. Die Zeile endet an einem Zeilenumbruch (welcher im Rückgabewert enthalten ist), EOF (Ende der Datei) oder bei length - 1 Bytes (je nachdem, was eher auftritt). Ist keine Länge angegeben, wird diese auf 1k bzw. 1024 Bytes gesetzt.
                          Einfacher Zeilenumbruch reicht muss kein CRLF sein sondern einfach \n


                          ok ich geb zu etwas falscher Zusammenhang aber das könnte hier weiterhelfen

                          Kommentar


                          • #14
                            Zitat von HStev
                            ok ich seh grad da hab ich allerdings mit
                            Code:
                            $data = fgets($this->socket, 128);
                            gearbeitet aber das hat funktioniert
                            Jo. Sicher funktioniert das.

                            Wenn nur bis zum nächsten Zeilenumbruch Daten eingelesen werden sollen
                            (FTP etc.), kann man das durchaus so handhaben. An Probleme stößt Du mit
                            dieser Methode aber dann, wenn Deine Daten auch Zeilenumbrüche enthalten
                            sollen können. Logisch ließen sich diese irgendwie Kodieren, sodass das ganze
                            wieder läuft. Nur muss dann auch immer der Server mitspielen.

                            Kommentar


                            • #15
                              So, ich habs jetz noch mal geändert, war doch noch ein Fehler drin, die endgültige Version sieht wie folgendermasen aus:

                              Senden der Daten über einen .Net Server:
                              Code:
                              public void send(string str)
                              {
                                  // write response ...
                                  byte[] data = Encoding.ASCII.GetBytes(str + "\n\n");
                                  this.cstream.Write(data, 0, data.Length);
                              }
                              Und der Empfang mit dem Php Client:
                              Code:
                              <?php
                              function receive($fp) {
                                $read = fgets($fp, 1024);
                                while($read != "\n") {
                                  $data .= $read;
                                  $read = fgets($fp, 1024);
                                }
                                return $data;
                              }
                              ?>
                              Hoffe es kann auch anderen helfen die genau so auf dem Schlauch standen wie ich

                              Kommentar

                              Lädt...
                              X