Проблемы с синапсами и строками с HTTPSend в Delphi 2010 - PullRequest
2 голосов
/ 12 марта 2010

Последние 2 дня я пытался разобраться с этой проблемой, и я действительно застрял. Надеюсь, что некоторые умные люди могут помочь мне.

Проблема в том, что у меня есть функция, которую я вызываю в потоке, который загружает файл (используя библиотеки Synapse) с веб-сайта, который ему передается. Тем не менее, я обнаружил, что время от времени появляются сайты, где он не будет загружать файл, но wget или Firefox / IE загрузят его без проблем.

Копаясь в этом, я нашел несколько любопытных вещей. Вот соответствующий код:

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;

Проблема в том, что когда я назначаю локальную переменную функции и даю ей URL-адрес, все работает. Однако при передаче переменной в функцию происходит сбой. У кого-нибудь есть идеи?

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

Я использую последнюю версию Synapse из их репозитория SVN (версия от 2 дней назад).

ПРИМЕЧАНИЕ. Файл, который я пытаюсь загрузить, , как известно, содержит вирус , программа, которую я пишу, предназначена для загрузки вредоносных файлов для анализа. Поэтому не запускайте файл после загрузки.

Тем не менее, я использую этот URL-адрес, потому что с этим я могу воспроизвести проблему.

Ответы [ 3 ]

4 голосов
/ 12 марта 2010

В вашем коде отсутствует важная деталь, как вы используете TMyThread класс. Тем не менее, вы пишете

время от времени появляются сайты, на которых файл не будет загружен, но wget или Firefox / IE загрузят его без проблем.

, что звучит как проблема синхронизации.

Использование локальной переменной работает каждый раз. Использование параметра функции работает только некоторое время. Это может быть вызвано тем, что параметр функции не содержит правильный URL , иногда .

Вы должны знать, что создание не приостановленного потока может привести к тому, что он начнет выполняться немедленно (и, возможно, даже завершиться), до следующей строки после того, как вызов конструкции даже начал выполняться. Поэтому установка любого свойства объекта потока после того, как поток был создан, может не сработать, так как выполнение потока может быть после точки, в которой свойство читается. Поле fTheUrl объекта потока изначально будет пустой строкой, поэтому то, будет ли поток загружать файл, будет зависеть от того, был ли он установлен ранее.

Ваше поле fTheUrl даже не защищено примитивом синхронизации. И процесс потока, и код в основном потоке могут получить к нему доступ одновременно. Распределение данных между потоками таким способом небезопасно и может привести к любой вещи - от неправильного поведения до реальных сбоев.

Если ваш поток действительно используется для загрузки одного файла, вы должны удалить доступ на запись к свойству и написать собственный конструктор с параметром для URL. Это правильно инициализирует поле перед началом потока.

Если вы загружаете несколько файлов в своей программе, вам не следует создавать поток для каждого. Используйте пул потоков (может быть только один), которым будут назначены файлы для загрузки. Для этого свойство потока является правильным решением, но тогда оно должно быть реализовано с синхронизацией, и поток должен блокироваться, когда файл не должен быть загружен, и разблокироваться, когда свойство установлено. Поток загрузки (или потоки) будет потребителем (ями) в реализации производитель-потребитель. Stack Overflow содержит вопросы и ответы по этому поводу в теге Delphi, в частности, в вопросах, где обсуждаются альтернативы Suspend() и Resume().

И последнее: не позволяйте необработанным исключениям избегать метода Execute(). Я не уверен, обрабатывает ли Delphi 2010 эти исключения в VCL, но необработанные исключения в потоке могут привести к таким проблемам, как сбой или зависание приложения.

0 голосов
/ 30 апреля 2010

Пожалуйста, обновите последнюю версию Synapse 127.

0 голосов
/ 13 марта 2010

Ну, мне почти стыдно сообщать об этом, но я обязан этим тем, кто нашел время, чтобы ответить.

Проблема не имела ничего , связанной с Synapse или TThread, но вместо этого имела отношение к факту, что URL чувствителен к регистру!

В моем полном приложении у меня была вспомогательная функция, которая понижала URL (по какой-то причине). Я удалил это, и все снова начало работать ...

...