Ir al contenido


Foto

[DELPHI] DownloadFile con WinSock


  • Por favor identifícate para responder
3 respuestas en este tema

#1 Khronos

Khronos

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 56 mensajes

Escrito 03 septiembre 2010 - 04:14

Hola, investigando un poco sobre el protocolo HTTP se me ocurrió hacer una función para descargar archivos de un servidor web mediante HTTP y WinSock. Este es el resultado:



delphi
  1. uses SysUtils, Classes, Windows, Forms, WinSock;
  2.  
  3. {Función: GetDomainName
  4. Ejemplo: Si le pasas "http://www.delphiaccess.com/forum/index.php?action=post;board=16.0"
  5. como parámetro te devuelve "www.delphiaccess.com"}
  6. function GetDomainName(const URL: AnsiString): AnsiString;
  7. var
  8. P1: integer;
  9. begin
  10.   P1:= Pos('http://', LowerCase(URL));
  11.   if P1 > 0 then
  12.     begin
  13.       result:= Copy(lowercase(URL), P1 + 7, Length(URL) - P1 - 6);
  14.       P1:= Pos('/', result);
  15.       if P1 > 0 then
  16.         result:= Copy(result, 0, P1 - 1);
  17.     end else
  18.       begin
  19.         P1:= Pos('/', URL);
  20.         if P1 > 0 then
  21.           result:= Copy(Lowercase(URL), 0, P1 - 1)
  22.         else result:= LowerCase(URL);
  23.       end;
  24. end;
  25.  
  26. {Función: GetFileWeb
  27. Ejemplo: Si le pasas "http://www.delphiaccess.com/forum/index.php?action=post;board=16.0"
  28. como parámetro te devuelve "/forum/index.php?action=post;board=16.0"}
  29. function GetFileWeb(const URL: AnsiString): AnsiString;
  30. var
  31. P1: integer;
  32. begin
  33.   P1:= Pos('http://', LowerCase(URL));
  34.   if P1 > 0 then
  35.     begin
  36.       result:= Copy(lowercase(URL), P1 + 7, Length(URL) - P1 - 6);
  37.       P1:= Pos('/', result);
  38.       if P1 > 0 then
  39.         result:= Copy(result, P1, Length(result) - P1 + 1);
  40.     end else
  41.       begin
  42.         P1:= Pos('/', URL);
  43.         if P1 > 0 then
  44.           result:= Copy(LowerCase(URL), P1, Length(URL) - P1 + 1)
  45.         else result:= LowerCase(URL);
  46.       end;
  47. end;
  48.  
  49. {Función: CleanHTTP
  50. Esta función se encarga de eliminiar las líneas de control
  51. que emplea el protocolo HTTP. El archivo comienza despues de #13#10#13#10.
  52.  
  53. Un ejemplo de las líneas que vamos a quitar con esta función:
  54.  
  55. HTTP/1.0 200 OK
  56. Date: Sat, 07 Aug 2010 23:25:05 GMT
  57. Expires: -1
  58. Cache-Control: private, max-age=0
  59. Content-Type: text/html; charset=ISO-8859-1
  60. Set-Cookie: PREF=ID=45985543825451c0:TM=1281223505:LM=1281223505:S=kPYwkz3GOI3idLv6; expires=Mon, 06-Aug-2012 23:25:05 GMT; path=/; domain=.google.es
  61. Set-Cookie: NID=37=rPl51eNebbKvxz3Abvlpje8AT-qMszIbpmDR-zJJjYlwRie55cmev5KE45t4kBPVmhsHPpWUqBwzwqI4rsndihEbd0OtrMJfMohVYI0lfxJ3U1uchrbJMA4SUVh2-uNz; expires=Sun, 06-Feb-2011 23:25:05 GMT; path=/; domain=.google.es; HttpOnly
  62. Server: gws
  63. X-XSS-Protection: 1; mode=block
  64. }
  65. procedure CleanHttp(var Mem: TMemoryStream);
  66. var
  67. i: integer;
  68. Separator: array [0..3] of AnsiChar;
  69. Mem2: TMemoryStream;
  70. begin
  71.   if Assigned(Mem) then
  72.     begin
  73.       for i := 0 to Mem.Size - 1 do
  74.         begin
  75.           Mem.Seek(i, 0);
  76.           Mem.Read(Separator, 4);
  77.           if (Separator[0] = #13) and (Separator[1] = #10) and (Separator[2] = #13)
  78.               and (Separator[3] = #10) then
  79.                 begin
  80.                   Mem2:= TMemoryStream.Create;
  81.                   Mem.Seek(i + 4, 0);
  82.                   Mem2.CopyFrom(Mem, Mem.Size - I - 4);
  83.                   Mem:= Mem2;
  84.                   break;
  85.                 end;
  86.         end;
  87.     end;
  88. end;
  89.  
  90.  
  91. {Función DownLoadFile
  92. URL: La dirección del archivo que vas a descargar.
  93. FileName: La ruta donde vas a guardar el archivo
  94. ProcessMessages: Por defecto está a True, hace que no se bloquee
  95. la aplicación con el bucle. Puedes cambiar su valor a False o eliminar la línea
  96. "if ProcessMessages then Application.ProcessMessages;" y los uses "Forms" si vas a
  97. trabajar en modo consola
  98.  
  99. Devuelve True si tiene éxito}
  100. function DownLoadFile(const URL: AnsiString; FileName: String; ProcessMessages: boolean = true): boolean;
  101. var
  102. WSA: TWSAData;
  103. Sock: TSocket;
  104. Hostent: PHostent;
  105. Ip: ^Integer;
  106. ReturnCode, i: integer;
  107. RHost: sockaddr_in;
  108. Http: AnsiString;
  109. szBuffer: array [0..1023] of AnsiChar;
  110. Stream: TMemoryStream;
  111. begin
  112. result:= false;
  113.   If WSAStartup(MakeWord(2,2), WSA) = 0 then
  114.     begin
  115.       Sock:= SOCKET(AF_INET, SOCK_STREAM, 0);
  116.       if Sock <> INVALID_SOCKET then
  117.           Hostent:= GetHostByName(PAnsiChar(GetDomainName(URL)));
  118.           if Hostent <> nil then
  119.             begin
  120.               Ip:= @Hostent.h_addr_list^[0];
  121.               RHost.sin_family:= AF_INET;
  122.               RHost.sin_port:= htons(80);
  123.               RHost.sin_addr.S_addr:= ip^;
  124.               if Connect(Sock, RHost, Sizeof(RHost)) = 0 then
  125.                 begin
  126.                   Http:= &#39;GET &#39; + GetFileWeb(URL) + &#39;  HTTP/1.0&#39;#13#10 +
  127.                   &#39;Host: &#39; + GetDomainName(URL) +  #13#10#13#10;
  128.                   send(Sock, Pointer(Http)^, Length(Http), 0);
  129.  
  130.                   try
  131.                   Stream:= TMemoryStream.Create;
  132.                     repeat
  133.                       if ProcessMessages then Application.ProcessMessages;
  134.                       FillChar(szBuffer, SizeOf(szBuffer), 0);
  135.                       ReturnCode:= recv(Sock, szBuffer, sizeof(szBuffer), 0);
  136.                       if ReturnCode > 0 then
  137.                         Stream.Write(szBuffer, ReturnCode);
  138.                     until ReturnCode <= 0;
  139.                   CleanHttp(Stream);
  140.                   if Stream.Size > 0 then result:= true;
  141.                   Stream.SaveToFile(FileName);
  142.                   finally
  143.                     Stream.Free;
  144.                   end;
  145.  
  146.                   ShutDown(Sock, SD_BOTH);
  147.                   CloseSocket(Sock);
  148.                 end;
  149.             end;
  150.     end;
  151.   WSACleanUp;
  152. end;



Ejemplo de uso:



delphi
  1. DownLoadFile(&#39;[url]http://www.google.es[/url]&#39;, &#39;C:\google.html&#39;);



Se puede hacer una clase TThread para descargar archivos de forma sencilla usando estas funciones.

Saludos.
  • 0

#2 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 03 septiembre 2010 - 04:23

Ah que interesante amigo Khronos. (y)

Salud OS

[off-topic]
En México quien estrena algo invita los tragos y tú has estrenado los prefijos :D :D :D
[/off-topic]

  • 0

#3 seoane

seoane

    Advanced Member

  • Administrador
  • 1.259 mensajes
  • LocationEspaña

Escrito 03 septiembre 2010 - 04:25

Da gusto ver que todavía hay gente a la que no le asusta bajar hasta el mismísimo winsock para experimentar un rato  (y)
  • 0

#4 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 03 septiembre 2010 - 06:16

Aunque existen formas de descarga mas sencillas de codificar, a veces merece la pena  romperse un rato la cabeza experimentando a bajo nivel. (y)

Saludos.
  • 0




IP.Board spam blocked by CleanTalk.