Pergunta

I foram tentando chegar ao fundo do problema e desligar durante os últimos 2 dias e eu estou realmente preso. Esperemos que algumas pessoas inteligentes podem me ajudar.

O problema é que eu tenho uma função que eu chamo em um segmento que baixa um arquivo (usando bibliotecas sinapse) a partir de um site que é passado para ele. No entanto, descobri que de vez em quando há locais onde não vai puxar para baixo um arquivo, mas wget ou Firefox / IE irá baixá-lo sem problema.

Indo para ele, eu encontrei algumas coisas curiosas. Aqui está o código relevante:

uses
//[..]
  HTTPSend,
  blcksock;

//[..]

type
  TMyThread = class(TThread)
  protected
    procedure Execute; override;
  private
    { Private declarations }
    fTheUrl: string;
    procedure GetFile(const TheUrl: string);
  public
    property thrd_TheUrl: string read fTheUrl write fTheUrl;
  end;

implementation

[..]

procedure TMyThread.GetFile(const TheUrl: string);
var
  HTTP: THTTPSend;
  success: boolean;
  sLocalUrl: string;
  IsSame : boolean;
begin

  HTTP := THTTPSend.Create;
  try
    HTTP.UserAgent :=
      'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727)';
    HTTP.ProxyHost := 'MYPROXY.COM';
    HTTP.ProxyPort := '80';

    sLocalUrl :=
      'http://web.archive.org/web/20071212205017/energizer.com/usbcharger/download/UsbCharger_setup_V1_1_1.exe';


   IsSame :=  SameText(sLocalUrl, sTheUrl); //this equals True when I debug

   ///
   ///
   /// THIS IS WHERE THE ISSUE BEGINS
   ///  I will comment out 1 of the following when debugging
   ///
    HTTP.HTTPMethod('GET', sLocalUrl); // ----this works and WILL download the file
    HTTP.HTTPMethod('GET', sTheUrl);  // --- this always fails, and HTTP.ResultString contains "Not Found"

    success := SysUtils.UpperCase(HTTP.ResultString) = 'OK';


    if HTTP.ResultCode > 0 then
      success := True; //this is here just to keep the value around while debugging
  finally
    HTTP.Free;
  end;
end;

procedure TMyThread.Execute
begin
   //fTheURL contains this value:  http://web.archive.org/web/20071212205017/energizer.com/usbcharger/download/UsbCharger_setup_V1_1_1.exe

   GetFile(fTheUrl);
end;

O problema é que quando eu atribuir uma variável local para a função e dar-lhe o URL diretamente, tudo funciona. No entanto, ao passar a variável para a função, ele falhar. Alguém tem alguma idéia?

    HTTP.HTTPMethod('GET', sLocalUrl); // ----this works and WILL download the file
    HTTP.HTTPMethod('GET', sTheUrl);  // --- this always fails, and HTTP.ResultString contains "Not Found"

Eu estou usando a versão mais recente Synapse de seu SVN repositório (versão de 2 dias atrás).

NOTA: O arquivo Eu estou tentando de download é conhecido por ter um vírus , o programa que eu estou escrevendo é para baixar arquivos maliciosos para análise. Assim, não executar o arquivo depois de baixá-lo.

No entanto, eu estou usando esse URL b / c este é o que eu posso reproduzir o problema com.

Foi útil?

Solução 2

Bem, eu estou quase envergonhado para denunciá-lo, mas devo isso aos que tomou o tempo para responder.

A questão tinha nada para fazer com Synapse, ou TThread, mas em vez disso tinha tudo a ver com o fato de que a URL é sensível a maiúsculas!

Na minha aplicação integral, eu tinha uma função auxiliar que em minúsculas do URL (por alguma razão). Eu removi que e tudo começou a trabalhar de novo ...

Outras dicas

Seu código está faltando o detalhe crucial como você usa classe TMyThread. No entanto, você escreve

de vez em quando há locais onde não vai puxar para baixo um arquivo, mas wget ou Firefox / IE irá baixá-lo sem problema.

que soa como um problema de tempo.

Usando a variável local funciona cada vez. Usando o parâmetro de função só funciona por algum tempo. Isso pode ser causado pelo parâmetro de função não contém a URL correta algum do tempo .

Você precisa estar ciente de que a criação de um segmento não-suspenso pode resultar em que começar a executar imediatamente (e possivelmente até mesmo a completa), antes da próxima linha após a chamada construção nem começou a ser executado. Definir qualquer propriedade do objeto segmento depois que o segmento foi criado pode, portanto, não trabalho, como a execução de thread pode ser passado o ponto onde a propriedade é leitura. O campo fTheUrl do objeto segmento vai ser uma cadeia vazia inicialmente, por isso se os downloads de rosca o arquivo vai depender de ele ser definido antes.

Seu campo fTheUrl é nem mesmo protegido por uma sincronização primitiva. Tanto o proc linha e o código no thread principal pode acessá-lo simultaneamente. O compartilhamento de dados dessa maneira entre threads é uma coisa perigosa para fazer e pode resultar em qualquer coisa de um comportamento errado acidentes reais.

Se o seu fio é realmente usado para baixar um arquivo único que você deve remover o acesso de gravação para a propriedade, e escrever um construtor personalizado com um parâmetro para o URL. Isso vai corretamente inicializar o campo antes que o segmento começa.

Se você estiver baixando vários arquivos em seu programa você deve realmente não criar um thread para cada um. Use um pool de threads (pode ser apenas um mesmo) que será atribuído os arquivos para download. Para que uma propriedade da linha é a solução certa, mas, em seguida, ele terá de ser implementado com a sincronização, eo segmento deve bloquear quando nenhum arquivo deve ser baixado e desbloquear quando a propriedade é definida. O fio download (ou threads) seria consumidor (s) em uma implementação produtor-consumidor. Stack Overflow tem perguntas e respostas sobre isso na tag Delphi, em particular nas questões onde as alternativas para Suspend() e Resume() são discutidos.

Uma última coisa: não deixe que exceções não tratadas escapar o método Execute(). Eu não tenho certeza sobre se alças Delphi 2010 essas exceções na VCL, mas não manipulado exceções em um thread pode levar a problemas como falhas de aplicativos ou congela.

Por favor, atualize última Synapse Revisão 127.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top