Несколько запросов на один и тот же IdHTTP внутри потока - PullRequest
0 голосов
/ 11 апреля 2019

У меня есть приложение, которое делает тысячи HTTP-запросов в течение дня.Для лучшей производительности я решил создать только один объект IdHTTP и использовать этот же объект для всех запросов.Вот где начинается проблема.При создании одного IdHTTP для каждого запроса все прошло нормально.Код довольно простой:

constructor HTTPThread.Create;
begin
  inherited Create(false);
  httpObject:= TIdHTTP.Create(Nil);
  sslObject:= TIdSSLIOHandlerSocketOpenSSL.Create(Nil);
  sslObject.SSLOptions.Method:= sslvTLSv1_2;
  httpObject.IOHandler:= sslObject;
  httpObject.Request.Accept:= frmHTTPRequests.Edit1.Text;
  httpObject.Request.UserAgent:= frmHTTPRequests.Edit3.Text;
  httpObject.ReadTimeout:= 15000;
  httpObject.HandleRedirects:= true;
  FreeOnTerminate:= true;
  OnTerminate:= TerminateProc;
end;


procedure HTTPThread.DoRequests;
var
    htmlSource: string;
begin
    try
      htmlSource:= httpObject.Get(Link);
      //a bunch of other stuff with HTML source
    except
      on E : Exception do
      Synchronize(procedure
      begin
        errorList.Add(E.Message);
        errorList.SaveToFile('Error.txt');
      end);
    end;
end;

Я создал это, за исключением сохранения файла Error.txt, чтобы посмотреть, что происходит ... Код иногда работает нормально для первых запросов 1k, иногда для первых 2k,различается.Неожиданно он начинает записывать в файл TXT ту же ошибку:

Сброс соединения по пиру.domain.com - Ошибка сокета # 10054

Я пытался отключить httpObject, пробовал httpObject.Request.Clear, похоже, ничего не работает.Есть ли шанс сделать эту работу?

1 Ответ

1 голос
/ 11 апреля 2019

По некоторым причинам Indy не закрывает сокет, когда сервер отвечает Connection reset by peer, поэтому вам нужно сделать это вручную.

    procedure HTTPThread.DoRequests;
    const
      MAX_TRIES_COUNT = 5;
    var
      htmlSource: string;
      TriesCount: Integer;
    begin
      TriesCount := 0;
      repeat
        try
          htmlSource:= httpObject.Get(Link);
          //a bunch of other stuff with HTML source
        except
          on E : Exception do
          begin
            if E.Message.Contains('by peer') then
            begin
              httpObject.Disconnect;
              // Try to solve network connection issues
              Continue;
            end;
            else
            begin
              // Some other error handlers
            end;
          end;
          inc(TriesCount);
        end;
      until (httpObject.ResponseCode = 200) or (TriesCount > MAX_TRIES_COUNT);
    end;

P.S. Я не рекомендую вам использовать Synchronize() для синхронизации потоков. Попробуйте использовать TCriticalSection или TMonitor .

...