glucke: php socketverbindungen

Hallo,

folgendes ist gegeben:

(pseudocode)

for($i; $i<100; $i++){

openSocketConnection();
setParameter($i);
readStream();
closeSocketConnection();

}

D.h. in einer Schleife öffne ich jeweils eine SocketVerbindung zu einem Remote-Server, setze verschiedene Parameter und lese dann die Antwort.
Bei EOF schliesse ich die Socketverdindung wieder.

Das geschieht etwa 100 mal.

Leider ist das ganze ziemlich langsam, obwohl jede Antwort nur aus jeweils etwa 500 Zeichen besteht. Ich habe die Zeit zwischen den Verbindungen gemessen, sie beträgt ca. 8 Sekunden.

Eine Antwort sieht so aus:
asf,asfe,asdf, 23423, 234, duId, 3223so, 432 --##--

das --##-- ist ein Marker, der das Ende der Übertragung darstellen soll.

Hat jemand eine Idee, wie sich der Vorgang beschleunigen lassen würde?
Vielen Dank!

ich poste nochmals den PHP Code (der nur testweise ausgeführt ist und somit durchaus verbesserungsbedürftig ist)

  
  
for($i=0; $i<100; $i++){  
  
$fp = fsockopen("tcp://example.com", 10502);  
fputs($fp, "tc=232"); //hier tc = zufallswert  
  
echo "neue Verbindung\n";  
  
if (!$fp) {  
    echo "$errstr ($errno)<br />\n";  
} else {  
  
    while (!feof($fp)) {  
  
        $string .=  fgets($fp);  
  
    }  
   // echo $string;  
    fclose($fp);  
}  
  
}  
  

  1. Hallo Glucke,

    da läuft ja schon einiges im code gegen den Baum:

    for($i=0;$i<100;$i++){  
    	$string='';  
    	// [link:http://de.php.net/manual/de/function.fsockopen.php]  
    	if(($fp=fsockopen("tcp://example.com",10502,$errno,$errstr,0.5))!==false){  
    		fputs($fp,"tc=232");  
    		while (!feof($fp)) {  
    			$string.=fgets($fp);  
    		}  
    		fclose($fp);  
    		continue;  
    	}  
    	echo "$errstr ($errno)<br />\n";  
    }
    

    Analysiere mal die vier Phasen nach ihrer absoluten Dauer:

    $deltaT=array(0.0,0.0,0.0,0.0);  
    for($i=0;$i<100;$i++){  
    	$time  =microtime(true);  
    	$string='';  
      
    	if(($fp=fsockopen("tcp://example.com",10502,$errno,$errstr,0.5))!==false){  
    		$deltaT[0]+=microtime(true)-$time;  
    		fputs($fp,"tc=232");  
    		$deltaT[1]+=microtime(true)-$deltaT[0];  
    		while (!feof($fp)) {  
    			$string.=fgets($fp);  
    		}  
    		$deltaT[2]+=microtime(true)-$deltaT[1];  
    		fclose($fp);  
    		$deltaT[3]+=microtime(true)-$deltaT[2];  
    		continue;  
    	}  
    	echo "$errstr ($errno)<br />\n";  
    }  
    echo "<pre>";  
    print_r($deltaT);  
    echo "</pre>";
    

    Danach weißt Du dann genau in welcher Phase es zu Verzögerungen kommt. Des weiteren wäre noch interessant, ob der host, der hier beispielhaft mit example.com angegeben ist, immer der selbe ist und wenn ja, ob der angesprochene Dienst persistente Verbindungen unterstützt.

    Gruß aus Berlin!
    eddi

    1. Hallo Eddi,
      vielen Dank für deine Hilfe.
      Ich habe mal zwei Durchläufe mit deiner Methode gemessen:

      <pre>Array
      (
          [0] => 0.025215864181519
          [1] => 1254666698.4846
          [2] => 14.002981901169
          [3] => 1254666698.4847
      )
      </pre><pre>Array
      (
          [0] => 0.05053973197937
          [1] => 2509333410.9473
          [2] => -1254666670.4601
          [3] => 3764000095.429
      )
      </pre>

      es scheint, dass das hier am zeitaufwendigsten ist:

      while (!feof($fp)) {
      $string.=fgets($fp);
      }

      1. Re:

        <pre>Array

        Die Zahlen können nicht stimmen. Poste bitte den entsprechenden Code, der diese Zahlen produziert haben soll!

        es scheint, dass das hier am zeitaufwendigsten ist:

        while (!feof($fp)) {
        $string.=fgets($fp);
        }

        Diese Schlussfolgerung ist anhand der Zahlen nicht nachvollziehbar.

        Gruß aus Berlin!
        eddi

        1. Hallo Eddi,

          hier der Code:

            
            
          for($i=0; $i<2; $i++){  
            
                  $time  =microtime(true);  
                  $string='';  
            
                  if(($fp=pfsockopen("tcp://example.com", 15025,$errno,$errstr,0.5))!==false){  
                          $deltaT[0]+=microtime(true)-$time;  
                          fputs($fp, "ti=878");  
                          $deltaT[1]+=microtime(true)-$deltaT[0];  
                          while (!feof($fp)) {  
                                  $string.=fgets($fp);  
                          }  
                          $deltaT[2]+=microtime(true)-$deltaT[1];  
                          fclose($fp);  
                          $deltaT[3]+=microtime(true)-$deltaT[2];  
            
                          echo "<pre>";  
                          print_r($deltaT);  
                          echo "</pre>";  
            
                          continue;  
            
                  }  
                  echo "$errstr ($errno)<br />\n";  
            
          
          
          1. Re:

            Die Zahlen stimmen also doch. Ich hab' einen Fehler gemacht, 'tschuldigung. Bitte versuche es mit folgendem nochmals:

            for($i=0; $i<2; $i++){  
              
                    $t1    =microtime(true);  
                    $string='';  
              
                    if(($fp=pfsockopen("tcp://example.com", 15025,$errno,$errstr,0.5))!==false){  
                            $deltaT[0]+=($t2=microtime(true))-$t1;  
                            fputs($fp, "ti=878");  
                            $deltaT[1]+=($t1=microtime(true))-$t2;  
                            while (!feof($fp)) {  
                                    $string.=fgets($fp);  
                            }  
                            $deltaT[2]+=($t2=microtime(true))-$t1;  
                            fclose($fp);  
                            $deltaT[3]+=($t1=microtime(true))-$t2;  
              
                            continue;  
                    }  
                    echo "$errstr ($errno)<br />\n";  
            }  
            echo "<pre>";  
            print_r($deltaT);  
            echo "</pre>";
            

            Weiterhin bleibt aber die Frage an Dich, ob der bei "example.com" angesprochene Dienst persistente Verbindungen unterstützt.

            Gruß aus Berlin!
            eddi

            1. Re:

              Die Zahlen stimmen also doch. Ich hab' einen Fehler gemacht, 'tschuldigung. Bitte versuche es mit folgendem nochmals:

              kein Problem, hätte mir ja auch auffallen können. Hier nochmals die neuen Werte:

              <pre>Array
              (
                  [0] => 0.025243997573853
                  [1] => 3.9100646972656E-05
                  [2] => 13.973631858826
                  [3] => 3.1948089599609E-05
              )
              </pre><pre>Array
              (
                  [0] => 0.050596952438354
                  [1] => 5.7220458984375E-05
                  [2] => 27.948299884796
                  [3] => 6.5803527832031E-05
              )
              </pre>

              Weiterhin bleibt aber die Frage an Dich, ob der bei "example.com" angesprochene Dienst persistente Verbindungen unterstützt.

              Der Dienst ist immer der gleiche, ob er persistente Verbindungen unterstützt, kann ich dir so nicht sagen. Kann man das irgendwie prüfen oder muss ich den entsprechenden Admin fragen?

              Dank die nochmals für die Unterstützung. Ich verstehe von Socket-Verbindungen leider fast überhaupt nichts.

              Gruss
              Glucke

              1. Re:

                <pre>Array
                (
                    [0] => 0.025243997573853
                    [1] => 3.9100646972656E-05
                    [2] => 13.973631858826
                    [3] => 3.1948089599609E-05
                )
                </pre><pre>Array
                (
                    [0] => 0.050596952438354
                    [1] => 5.7220458984375E-05
                    [2] => 27.948299884796
                    [3] => 6.5803527832031E-05
                )
                </pre>

                Demnach ist tatsächlich das Auslesen (2) das verzögernde Moment. Aber auch fputs und fclose (1, 3) erscheint mir unnatürlich lang. Ist das eine Windowskiste, auf dem der Code läuft? (Eigentlich ist dafür die DNS-Auflösung (0) aber zu schnell.) Sitz ein Paketfilter/Firewall dazwischen? Andere Ansätze, auch den mit einer dauerhaften Verbindung, sehe ich nicht, wo Du als Client das ganze beschleunigen könntest.

                Gruß aus Berlin!
                eddi

                1. hi

                  Demnach ist tatsächlich das Auslesen (2) das verzögernde Moment. Aber auch fputs und fclose (1, 3) erscheint mir unnatürlich lang. Ist das eine Windowskiste, auf dem der Code läuft? (Eigentlich ist dafür die DNS-Auflösung (0) aber zu schnell.) Sitz ein Paketfilter/Firewall dazwischen? Andere Ansätze, auch den mit einer dauerhaften Verbindung, sehe ich nicht, wo Du als Client das ganze beschleunigen könntest.

                  nein, der Code läuft auf einem Linux-Rechner. Ob ein Paketfilter bzw. eine Firewall da ist, muss ich prüfen.

                  Mal dumm gefragt: wenn ich immer den gleichen Host anfrage, muss ich dazu die Socketverbindung für jeden Request schliessen und wieder öffen? Könnte nicht irgendwie die Verbindung bestehen bleiben?

                  glucke

                  1. Re:

                    Mal dumm gefragt: wenn ich immer den gleichen Host anfrage, muss ich dazu die Socketverbindung für jeden Request schliessen und wieder öffen? Könnte nicht irgendwie die Verbindung bestehen bleiben?

                    Das wäre dann eine persistente Verbindung. Es käme auf den Versuch an:

                    if(($fp=pfsockopen("tcp://example.com", 15025,$errno,$errstr,0.5))!==false){  
                    	for($i=0; $i<2; $i++){  
                    		$string='';  
                    		fputs($fp, "ti=878");  
                    		  
                    		while (!feof($fp)) {  
                    			$string.=fgets($fp);  
                    			if(substr($string,-6)=='--##--'){  
                    				# echo $string  
                    				break;  
                    			}  
                    		}  
                            }  
                    	fclose($fp);  
                    }  
                    echo "$errstr ($errno)<br />\n";
                    

                    Gruß aus Berlin!
                    eddi

                    1. hi eddi,

                      super. Persistente Verbindung scheint zu klappen. Mit der ersten Anfrage, die ich stelle, erhalte ich gewisse Daten, aus denen ich dann weitere Anfragen stelle. Leider scheint das mit fputs nicht zu funktionieren.

                        
                        
                      $string = '';  
                        
                      if(($fp=pfsockopen("tcp://example.com", 10224,$errno,$errstr,0.5))!==false){  
                        
                       fputs($fp, "ti=123");  
                        
                       while (!feof($fp)) {  
                              $string .=  fgets($fp);  
                              }  
                        
                      $string = '';// hier wird der string in einen array gepackt, um ihn dann weiter unten pro Durchlauf auszulesen. Der Übersichtlichkeit halber habe ich diese Operation nicht dargestellt. Versichert sei, dass die Werte unten korrekt übergeben wurden.  
                        
                              for($i=0; $i<10; $i++){  
                        
                                      fputs($fp, "ti=424");//hier werden pro Schleifendurchlauf andere Werte gesetzt, die wie oben beschrieben aus dem array übernommen wwerden.  
                        
                                      while (!feof($fp)) {  
                                             $string.=fgets($fp); //es wird nichts ausgegeben  
                                              if(substr($string,-6)=='--##--'){  
                                                      # echo $string  
                                                      break;  
                                              }  
                                      }  
                              }  
                              fclose($fp);  
                      }  
                        
                      
                      

                      Geht das mit fputs also nicht, sondern muss man das anders machen?

                      Vielen Dank und Gruss
                      Glucke

                      1. Re:

                        $string = '';
                        $array=array('ti=324','xy=444',...),

                        if(($fp=pfsockopen("tcp://example.com", 10224,$errno,$errstr,0.5))!==false){

                        fputs($fp, "ti=123");

                        while (!feof($fp)) {
                                $string .=  fgets($fp);
                                }

                        $string = '';// hier wird der string in einen array gepackt, um ihn dann weiter unten pro Durchlauf auszulesen. Der Übersichtlichkeit halber habe ich diese Operation nicht dargestellt. Versichert sei, dass die Werte unten korrekt übergeben wurden.

                        for($i=0; $i<10; $i++){

                        fputs($fp, $array[$i]);

                        while (!feof($fp)) {
                                               $string.=fgets($fp); //es wird nichts ausgegeben
                                                if(substr($string,-6)=='--##--'){
                                                        # echo $string
                                                        break;
                                                }
                                        }
                                }
                                fclose($fp);
                        }

                          
                        So würde ich es jetzt verstehen und lösen.  
                          
                          
                        Gruß aus Berlin!  
                        eddi
                        
                        1. hi,

                          genauso habe ich es auch gedacht und gemacht.
                          Leider wird mir nach dem ersten fputs nichts ausgegeben. Ich spekulierte, dass fputs ja immer alles hinten dran hängt,
                          also im ersten Durchlauf
                          ti=123
                          im zweiten
                          ti=123xy=444

                          etc.

                          Na gut, danke dir. Werd wohl noch ein bisschen testen müssen.

                          Gruss
                          glucke

                          1. Hallo,

                            Leider wird mir nach dem ersten fputs nichts ausgegeben. Ich spekulierte, dass fputs ja immer alles hinten dran hängt, also im ersten Durchlauf
                            ti=123
                            im zweiten
                            ti=123xy=444

                            nein, fputs() sendet die Daten exakt so wie angegeben - was einmal gesendet ist, ist weg und wird auch nicht wiederholt oder gesammelt.
                            Es kann aber sein, dass der Server, den du ansprichst, das tut. Dann bräuchte er tatsächlich das Schließen und das erneute Öffnen der Verbindung, um eine neue Anfrage entgegenzunehmen - mit den dadurch entstehenden Nachteilen wie z.B. Wartezeiten.

                            So long,
                             Martin

                            --
                            F: Was ist ekliger als ein angebissener Apfel mit einem Wurm drin?
                            A: Ein angebissener Apfel mit einem halben Wurm.
                            1. Hallo,

                              nein, fputs() sendet die Daten exakt so wie angegeben - was einmal gesendet ist, ist weg und wird auch nicht wiederholt oder gesammelt.
                              Es kann aber sein, dass der Server, den du ansprichst, das tut. Dann bräuchte er tatsächlich das Schließen und das erneute Öffnen der Verbindung, um eine neue Anfrage entgegenzunehmen - mit den dadurch entstehenden Nachteilen wie z.B. Wartezeiten.

                              danke dir! Gut zu wissen. Leider erreiche ich den zuständigen Admin die Tage nicht, deshalb muss ich rumprobieren. wird schon irgendwie klappen.

                              gruss
                              glucke

                            2. @glucke:

                              Dann bräuchte er tatsächlich das Schließen und das erneute Öffnen der Verbindung, um eine neue Anfrage entgegenzunehmen - mit den dadurch entstehenden Nachteilen wie z.B. Wartezeiten.

                              Jep. Der Dienst unterstützt demnach leider keine persistente Verbindung.

                              Gruß aus Berlin!
                              eddi