[PHP] met 1 socket meerdere bestanden 'downloaden'

Pagina: 1
Acties:

Onderwerpen


  • frickY
  • Registratie: Juli 2001
  • Laatst online: 18-09 14:42
Ik heb een PHP-scriptje geschreven welke de URL opent welke ik hem geef, en hieruit alle '<a href=*>'-jes pakt. Vervolgens gaat hij al deze gevonden links downloaden, mits deze aan een bepaalde extensie voldoen. Tot hier geen enkel probleem.

Nu gebruik ik voor zowel het uitlezen van de pagina, als het 'downloaden' van de bestanden, de functie fsockopen(). Ik schrijf de HTTP-headers weg om het bestand dat ik wil te krijgen, sluit de socket, en sla het bestand op. Dit opnieuw en opnieuw voor elk bestand.

Nu vraag ik mij af of dit niet veel efficienter kan.
is het niet mogelijk om 1x een socket-verbinding naar de host te sturen, en deze open te houden tot je alle bestanden hebt welke je wilt. Volgens mij scheelt dat een hoop 'overhead', en gaat dit veel sneller.

Nu gebruik ik bijvoorbeeld om een bestand te downloaden;
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function getFile($host, $file) {
  $fp = fsockopen($host, 80, $errno, $errstr, 30);
  if (!$fp) {
     echo "$errstr ($errno)<br />\n";
  } else {
     $out = "GET $file HTTP/1.1\r\n";
     $out .= "Host: $host\r\n";
     $out .= "Connection: Close\r\n\r\n";
     fwrite($fp, $out);

     $line = "";
     while (!feof($fp) ) {
      $line .= fgets($fp, 128);
     }
     saveasfile($line);
     fclose($fp);
  }
}


Maar stel ik wil 100 bestanden vanaf datzelfde domein. Kan dat, en zo ja, hoe?
Kan me voorstellen dat ik iets met de 'connection: close' header moet doen, maar kom er niet uit. Iemand een idee of het kan?

[ Voor 6% gewijzigd door frickY op 26-08-2004 22:18 ]


  • pistole
  • Registratie: Juli 2000
  • Laatst online: 19:48

pistole

Frutter

misschien een niet geheel terechte reaktie mijnerzijds, maar... waarom doe je dit in php?
Nu vermoed ik dat je php onder windows hebt draaien, wat jammer is. Want als je een OS met krachtige shell scripting hebt, dan had dit veel simpeler gekunt.

Overigens lijkt het me met php ook veel makkelijker kunnen:

1) url openen -> opslaan in variabele of file
2) variabele of file parsen -> array met downloadable urls
3) array doorlopen en alle urls opslaan

Zoiets toch?
Wat betreft die socket: AFAIK gaat dat niet echt lukken (1 socket) ivm de werking van het HTTP protocol.

Ik frut, dus ik epibreer


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 21:01
Je kunt sequentieel bestanden downloaden over een enkele verbinding met de functionaliteit van HTTP 1/1. Als je de curl-library voor PHP hebt geïnstalleerd kan het daarmee wat makkelijker dan als je het zelf moet implementeren, hoewel het niet echt moeilijk is als je deze code al hebt.

De details vind je in sectie 8 van de HTTP 1.1-specificatie, over persistent connections. (Keep-alive en pipelining.)

  • frickY
  • Registratie: Juli 2001
  • Laatst online: 18-09 14:42
Ik doe nu precies wat jij voorstelt. Ik loop een array met bestanden door en die sla ik 1 voor 1 op.
Maar voor elk bestand wordt het domein-naam dus geresolved, wordt een verbnding geopent naar die server (handshakes en whatever), dan wordt het bestand gedownload, en de verbinding weer gesloten. En dat keer op keer op keer.
Het werkt wel, maar het lijkt me zo in-efficient...

De reden dat ik dit in PHP doe is omdat dit verder totaal niets belangrijks is maar ik even snel een aantal opendirs naar mn schijf wil trekken, en ik php als mn broekzak ken ;) Ben alleen wat minder bekened met een HTTP-protocol.


Kijk, dat ziet er bruikbaar uit! Ik ga het eens even doorlezen. Thanks!
Het opent alvast met precies de redenen te noemen waarom ik dit wil;
- By opening and closing fewer TCP connections, CPU time is saved
in routers and hosts (clients, servers, proxies, gateways,
tunnels, or caches), and memory used for TCP protocol control
blocks can be saved in hosts.

- HTTP requests and responses can be pipelined on a connection.
Pipelining allows a client to make multiple requests without
waiting for each response, allowing a single TCP connection to
be used much more efficiently, with much lower elapsed time.

- Network congestion is reduced by reducing the number of packets
caused by TCP opens, and by allowing TCP sufficient time to
determine the congestion state of the network.

- Latency on subsequent requests is reduced since there is no time
spent in TCP's connection opening handshake.

- HTTP can evolve more gracefully, since errors can be reported
without the penalty of closing the TCP connection. Clients using
future versions of HTTP might optimistically try a new feature,
but if communicating with an older server, retry with old
semantics after an error is reported.

[ Voor 55% gewijzigd door frickY op 26-08-2004 22:32 ]


  • pistole
  • Registratie: Juli 2000
  • Laatst online: 19:48

pistole

Frutter

frickY schreef op 26 augustus 2004 @ 22:29:
Ik doe nu precies wat jij voorstelt. Ik loop een array met bestanden door en die sla ik 1 voor 1 op.
Maar voor elk bestand wordt het domein-naam dus geresolved, wordt een verbnding geopent naar die server (handshakes en whatever), dan wordt het bestand gedownload, en de verbinding weer gesloten. En dat keer op keer op keer.
Het werkt wel, maar het lijkt me zo in-efficient...
SYN+SYN/ACK+FIN+FIN/ACK
Dat zijn dus 4 extra pakketjes per download. Is dat significant?
Mag aannemen dat resolving wel gecashed wordt...
edit:

whatever ;)

[ Voor 3% gewijzigd door pistole op 26-08-2004 22:34 ]

Ik frut, dus ik epibreer


  • frickY
  • Registratie: Juli 2001
  • Laatst online: 18-09 14:42
Ik zie nu dat hiervoor de functie pfsockopen kan worden gebruikt. Kan alleen nergens vinden hoe 8)7

Verwijderd

In HTTP/1.1 staat 'Connection' standaard op 'keep-alive', dus die regel mag je weglaten. Bij het ontvangen van de data moet je de header scannen op 'Content-Length'. Zoveel bytes kan je verwachten. Heb je die binnen, dan stuur je de volgende request. Simpel

Vervelender wordt het als de 'Transfer-Encoding' op 'chunked' staat, maar dat heb je alleen als je de output van een CGI proces opvraagt. Maar dat is een heel verhaal en ik heb niet het idee dat je dat gaat doen.

  • frickY
  • Registratie: Juli 2001
  • Laatst online: 18-09 14:42
Als ik deze headers verstuur naar een willkeurige webserver;
code:
1
2
3
GET /index.php HTTP/1.1
Host: webserver.nl
Connection: Keep-Alive


Krijg ik dit terug;
code:
1
2
3
4
5
6
7
HTTP/1.1 200 OK
Date: Thu, 26 Aug 2004 21:47:06 GMT
Server: Apache/1.3.28
Keep-Alive: timeout=15, max=100
connection: Keep-Alive
Transfer-Encoding: cunked
content-type: text/html


Na de laatste header volgt een lege regel, en vervlens een regel met alleen "102e"
Vervolgens 2 lege regels, en dan de body van de opgevraagde pagina...
Als ik n html pagina opvraag krijg ik het volgende (niet gecunked dus)
code:
1
2
3
4
5
6
7
8
9
10
HTTP/1.1 200 OK
Date: Thu, 26 Aug 2004 22:02:35 GMT
Server: Apache/1.3.28 (Unix) PHP/4.3.3 mod_ssl/2.8.15 OpenSSL/0.9.7c
Last-Modified: Tue, 30 Dec 2003 09:52:14 GMT
ETag: "2c00a5-15c5-3ff14ace"
Accept-Ranges: bytes
Content-Length: 5573
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html


Nu zou ik dus tot 5573 tekens moeten uitlezen.. en dan trap ik mn volgende GET-request erdoor heen? Of moet ik eerst een ander iets versturen om aan te geven dat het volgende request eraan komt?



Het lijkt te zijn gelukt! Ik doe 1x een pfsockopen() en vraag vervolgens 2 verschillende HTML-pagina's op;
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
HTTP/1.1 200 OK
Date: Thu, 26 Aug 2004 22:07:49 GMT
Server: Apache/1.3.28 (Unix) PHP/4.3.3 mod_ssl/2.8.15 OpenSSL/0.9.7c
Last-Modified: Tue, 30 Dec 2003 09:52:14 GMT
ETag: "2c00a5-15c5-3ff14ace"
Accept-Ranges: bytes
Content-Length: 5573
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html

HTTP/1.1 200 OK
Date: Thu, 26 Aug 2004 22:07:49 GMT
Server: Apache/1.3.28 (Unix) PHP/4.3.3 mod_ssl/2.8.15 OpenSSL/0.9.7c
Last-Modified: Fri, 23 Jul 2004 10:55:25 GMT
ETag: "2c0103-1154-4100ee9d"
Accept-Ranges: bytes
Content-Length: 4436
Connection: close
Content-Type: text/html

Nu even uitzoeken hoe dat zit met cunked data zit.. I want it all =)

[ Voor 77% gewijzigd door frickY op 27-08-2004 00:09 ]


Acties:
  • 0 Henk 'm!

Verwijderd

chunked data: eerst een hexadecimaal getal (met decimale waarde X), gevolgd door \r\n, gevolgd door X bytes, gevolgd door \r\n. Dit gaat door tot X=0. Wederom simpel :)

[ Voor 6% gewijzigd door Verwijderd op 27-08-2004 00:34 ]


Acties:
  • 0 Henk 'm!

Verwijderd

oeps.... moest edit zijn ipv reply. Ja, ik weet 't, ik moet gaan slapen.

[ Voor 125% gewijzigd door Verwijderd op 27-08-2004 00:34 ]

Pagina: 1