solaris-ch
Goto Top

Fgets langsam

Hallo zusammen

ich habe ein Problem mit fgets(). Folgendes Script dreht ewig lange. Dies aber nicht, weil der Server so langsam antwortet, sondern, weil fgets so lange rumnudelt.

$fp 	= fsockopen("ssl://hostname:443/blubb",443, $errno, $errstr, 30);  
$body = "  

<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:urn=\"urn:blubb.hostname\">  
   <soapenv:Header/>
   <soapenv:Body>
      <urn:request>
         <urn:cli>0441111111</urn:cli>
         <urn:technology>adsl</urn:technology>
      </urn:request>
   </soapenv:Body>
</soapenv:Envelope>";  

$body_length = strlen($body);

$data 	= "POST https://hostname/blubb?wsdl HTTP/1.1  
Content-Type: text/xml;charset=UTF-8
SOAPAction: \"\"  
User-Agent: Jakarta Commons-HttpClient/3.1
Content-Length: $body_length
Authorization: Basic aaaaaaaaa
Host: hostname
Cookie: \$Version=0; JSESSIONID=EE4D5DSDSAD15E988A4BE6C9B51AB.0308; \$Path=/";  

$data .= $body;

// echo $data;

fwrite($fp, $data);
while (!feof($fp)) {
	echo fgets($fp)."<br>";  
}

Das dauert etwa 4 Minuten. Wenn ich nur den Teil bis zur while - Schlaufe knattern lasse, gehts 2 Sekunden. Ich bin ratlos. Einerseits ist klar wo das Problem liegt, aber nicht wie ich es beheben kann.

Der Output vom Server sieht übrigens so aus:

HTTP/1.1 200 OK
<br>Date: Wed, 22 Sep 2010 05:22:19 GMT
<br>Server: Apache
<br>X-Powered-By: Servlet 2.4; JBoss-4.0.3SP1 (build: CVSTag=JBoss_4_0_3_SP1 date=200510231054)/Tomcat-5.5
<br>Vary: Accept-Encoding,User-Agent
<br>Connection: close
<br>Content-Type: text/xml;charset=utf-8
<br> 
<br><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body><response xmlns="urn:hostname"><status><ccode>OK</ccode><message>Q00 This telephone line is suitable for xDSL. </message></status><serviceprofile><ccode>OK_max300_100</ccode><message>max. 300 Kbps downstream / 100 Kbps upstream</message></serviceprofile><serviceprofile><ccode>OK_max5000_500</ccode><message>max. 5000 Kbps downstream / 500 Kbps upstream</message></serviceprofile><serviceprofile><ccode>OK_max1000_100</ccode><message>max. 1000 Kbps downstream / 100 Kbps upstream</message></serviceprofile><serviceprofile><ccode>OK_max6000_600</ccode><message>max. 6000 Kbps downstream / 600 Kbps upstream</message></serviceprofile><networkprofile><ccode>OK_5000_500</ccode><message>5000 Kbps downstream / 500 Kbps upstream</message><customerclass>business</customerclass></networkprofile><networkprofile><ccode>OK_5000_500</ccode><message>5000 Kbps downstream / 500 Kbps upstream</message><customerclass>residential</customerclass></networkprofile><linetype>analog</linetype></response></soapenv:Body></soapenv:Envelope><br>  

Bedanke mich jetzt schon für die (wie immer) zahlreichen Tipps!

Grüsse, tom

Content-ID: 151497

Url: https://administrator.de/contentid/151497

Ausgedruckt am: 15.11.2024 um 23:11 Uhr

SlainteMhath
SlainteMhath 22.09.2010 um 09:27:00 Uhr
Goto Top
Moin,

versuchs mal mit stream_get_contents() oder fread() anstatt dem fgets() oder du setzt 'mal einen Timeout mit socket_set_timeout().

lg,
Slainte
76109
76109 22.09.2010 um 09:41:49 Uhr
Goto Top
Hallo solaris-ch!

Also, ich habe Null Ahnung von PHP, frage mich allerdings, wie aus einem Stream gelesen werden kann, in den zuvor gerade noch geschrieben wurde und der Positionszeiger auf das Ende zeigt. Sollte da nicht der Positionszeiger erst per FSEEK - oder sowas in der Art - auf 0 gesetzt werden? Möglicherweise stehen die Chance dann besser, dass die While-Schleife ein FEOF findet.

Gruß Dieter
solaris-ch
solaris-ch 22.09.2010 um 10:20:48 Uhr
Goto Top
Hi Dieter

besten Dank. Das hat leider nichts gebracht face-sad

Trotzdem danke!

Gruss, tom
solaris-ch
solaris-ch 22.09.2010 um 10:40:30 Uhr
Goto Top
Hallo Slainte

hilft alles nix :/

Gruss, tom
solaris-ch
solaris-ch 22.09.2010 um 18:42:37 Uhr
Goto Top
Hallo zusammen

Problem gelöst. Und für die Nachwelt hier noch die Lösung:

man muss die HTTP Spezifikationen genau anschauen. Dort sieht man, dass man eine Connection auch Header-mässig schliessen muss.

Was ist nun passiert, bei meinem Script, bevor ich auf die Lösung gekommen bin.

Mein Skript hat die Socketverbindung eröffnet und den Header, sowie den Body geschickt und darauf gewartet, das der Server den Empfang quasi bestätigt, damit es dann die Socket-Verbindung hätte kappen können. Da aber die Header Connection nie geschlossen wurde, wartete die Socketverbindung bis zum Timeout des Servers (ca 4 Minuten) und erst dann gings - wenn überhaupt - weiter.

Was habe ich gemacht, das es der Request nun innerhalb 2 Sekunden abgehandelt wird?
Mir helfen und zeigen lassen wie man diese Verbindung kappt. Ist - wenn man weiss wie - ganz einfach. So habe ich am Ende des Headers (bevor der Body gesendet wird!) folgendes eingefügt:

Connection: close\r\n\r\n

Und siehe da, es geht. Das ganze Script sieht so aus:

public function doLineCheck($cli){
		include_once("config/config.inc.php");  

		$xipxml = "";  
		//		$time = array();
		$fp 	= fsockopen("ssl://pkasdasdasdasdasdasdaeck_v1",443, $errno, $errstr, 30);  
		//		if (!$fp) { // wenn verbindung nicht klappt, fault setzen
		//			$this->xip_fault .= "error: $errstr ($errno)<br />\n"; 
		//		} else {	// wenn verbindung ok, dann weiter

		$body = "  
<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:urn=\"urn:swiasdasdadade.net\">  
   <soapenv:Header/>
   <soapenv:Body>
      <urn:request>
         <urn:cli>$cli</urn:cli>
         <urn:technology>adsl</urn:technology>
      </urn:request>
   </soapenv:Body>
</soapenv:Envelope>";  
			
		$body_length = strlen($body);

		$header 	= "POST https://pkg-xip-iasdasdasdasdnecheck_v1?wsdl HTTP/1.1  
Content-Type: text/xml;charset=UTF-8
SOAPAction: \"\"  
User-Agent: Jakarta Commons-HttpClient/3.1
Content-Length: $body_length
Authorization: Basic ZGasdasdasdasd
Host: xip-t02.asdasd.net
Cookie: \$Version=0; JSESSIONID=FE4D5DA06SDASDASD51AB.0308; \$Path=/
Connection: close\r\n\r\n";  
		$data = $header . $body;
		fwrite($fp,$data);
		while (!feof($fp)) {
			$xipxml .= fgets($fp,1024);
		}
		fclose($fp);
		//		}
		if(preg_match("@<ns1:errormessage>(.*?)<\/ns1:errormessage>@", $xipxml, $treffer)){  
			$this->xip_fault .= "CLICHECK ERROR: " . $treffer[1] . " Reasons: VoIP Number, ULL Number or Telephone Exchange System.";  
		}else{

			preg_match("@<linetype>(.*?)<\/linetype>@", $xipxml, $treffer);  
			$this->xip_linetype = $treffer[1];

			if(!isset($xip_fault)){ // wenn kein fehler, variabeln zur�ckliefern
				if(isset($xip_linetype)) return $xip_linetype;
			}else{ // wenn fehler, fault zur�cksenden
				return $xip_fault;
			}

		}
	}

Nun, so einfach ist das. Gekostet hat's mich eine Woche. Aber es ist meist stets dasselbe kleine, miese, dreckige,... Detail.

Beste Grüsse und Dank an alle die mir geholfen haben!

Tom
dog
dog 22.09.2010 um 20:41:23 Uhr
Goto Top
Deine Erklärung ist völlig Quark (deine Lösung aber eine mögliche).

Dein Code erwartet immer, dass der Stream, aus dem gelesen wird ein EOF hat.
Auf Deutsch: Du kannst while(feof()) nur dann benutzen, wenn die Datei, die gelesen wird, ein vorbestimmtes Ende hat.

Das ist aber bei HTTP niemals der Fall, denn auf TCP-Ebene hat ein Stream kein Ende, sondern nur innerhalb des HTTP-Protokolls.
Du kannst HTTP darum nur korrekt laden, wenn du die Antwort-Header des Servers interpretierst und daraus die Content-Length bzw. das Transfer-Encoding ableitest und mit fread() die korrekte Anzahl der Bytes liest.

Dein Code wird übrigens prima explodieren, wenn der Server mal als Transfer-Encoding chunked benutzt.

Darum macht man sowas auch nicht selbst, sondern benutzt das cURL Library o.Ä. - da gibt es solche Fehler nicht.