Jak umieścić kod serwera http w wątkach?

0

Witam,
jak umieścić kod serwera http w wątkach tak aby każde żądanie / lub żądania z danego IP odbywały się w osobnych wątkach.

Kod wątku (przykład):

unit Unit2;
 
interface
 
uses
  Classes;
 
type
  TMojWatek = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
  end;
 
implementation
 
{ Important: Methods and properties of objects in visual components can only be
  used in a method called using Synchronize, for example,
 
      Synchronize(UpdateCaption);
 
  and UpdateCaption could look like,
 
    procedure TMojWatek.UpdateCaption;
    begin
      Form1.Caption := 'Updated in a thread';
    end; }
 
{ TMojWatek }
 
procedure TMojWatek.Execute;
begin
  { Place thread code here }
end;
 
end.

Kod HTTPServer1CommandGet (przykład):

 
procedure TForm1.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
  var
  LFilename: string;
  LPathname: string;
  Ext: string;
  OldIdHttpSessionId: Variant;
  Aout: array[0..5] of Variant;
begin
  LFilename := ARequestInfo.Document;  //Co chce dostać przeglądarka, jaki plik
  if LFilename = '/' then
    LFilename := '/index.htm';
  LPathname := FHTMLDir + LFilename;
  if FileExists(LPathname) or (LFilename = '/index.htm')  then
  begin
      if LFilename = '/index.htm' then  //Sprawdza czy plik istnieje wykonuje instrukcje tylko dla index.htm
        begin
          {sprawdzanie, logowanie}
          Form1.memo1.Lines.Append(CheckParamValue(ARequestInfo,'userName'));
          PGGetCookie(ARequestInfo, 'IDHTTPSESSIONID', OldIdHttpSessionId); //Odczytuje Cookie
          loginMessage:=SetSessionToUser([CheckParamValue(ARequestInfo,'userName'),CheckParamValue(ARequestInfo,'userPass'),ARequestInfo.Session.SessionID, OldIdHttpSessionId]);
          ARequestInfo.Params.SaveToStream(strumien);
          ManageUserSession(AContext, ARequestInfo, AResponseInfo);
          ServeVirtualFolder(AContext, ARequestInfo, AResponseInfo);
      end;

    if LFilename = '/index.htm0' then
      begin

      end
      else
        begin
        AResponseInfo.ContentStream := TMemoryStream.Create();
        t[CompareMSWithCS(LFilename)].Position:=0;
        t[CompareMSWithCS(LFilename)].SaveToStream(AResponseInfo.ContentStream);
        Ext:= y[CompareMSWithCS(LFilename)];
        end;
    if AResponseInfo.ContentStream <> nil then
    begin

      AResponseInfo.ResponseNo:= 200;
      Ext:= y[CompareMSWithCS(LFilename)];

      { Wysyła Nagłówki Do Przeglądarki Aby Wiedziała Co Odbiera }
      if AnsiEndsText('.jpg', Ext) then
        begin
          AResponseInfo.ContentType:= 'image/jpeg';
          exit;
        end;
      if AnsiEndsText('.png', Ext) then
        begin
          AResponseInfo.ContentType:= 'image/png';
          exit;
        end;
      if AnsiEndsText('.gif', Ext) then
        begin
          AResponseInfo.ContentType:= 'image/gif';
          exit;
        end;
      if AnsiEndsText('.eot', Ext) then
        begin
          AResponseInfo.ContentType:= 'text/plain';
          exit;
        end;
      if AnsiEndsText('.svg', Ext) then
        begin
          AResponseInfo.ContentType:= 'text/plain';
          exit;
        end;
        if AnsiEndsText('.ttf', Ext) then
        begin
          AResponseInfo.ContentType:= 'text/plain';
          exit;
        end;
      if AnsiEndsText('.woff', Ext) then
        begin
          AResponseInfo.ContentType:= 'text/plain';
          exit;
        end;
      if AnsiEndsText('.js', Ext) then
        begin
          AResponseInfo.ContentType:= 'text/javascript';
          exit;
        end;
      if AnsiEndsText('.css', Ext) then
        begin
          AResponseInfo.ContentType:= 'text/css';
          exit;
        end;
      if AnsiEndsText('.html', Ext) then
        begin
          AResponseInfo.ContentType:= 'text/html';
          exit;
        end;
      if AnsiEndsText('.htm', Ext) then
        begin
          AResponseInfo.ContentType:= 'text/html';
          exit;
        end;
    end;
  end;
  AResponseInfo.ResponseNo:= 404;
end;

Jak np. tę procedurę TForm1.IdHTTPServer1CommandGet /i inne umieścić w TThread, nowe połączenie / wywołanie - nowy wątek.
Nadchodzi Request - tworzy się nowy wątek obsługujący TForm1.IdHTTPServer1CommandGet i inne procedury/funkcje mu potrzebne , wykonuje co ma wykonać odsyła co ma odesłać i wątek jest usuwany. Aktualnie jest taka sytuacja, że wiele zapytań w krótkim czasie zawiesza program lub wywala błędy, głównie z funkcjami/procedurami obsługującymi bazę danych/ oraz elementy wizualne serwera.

0

Z Indykiem najlepiej radzi sobie tutaj @kAzek. Jednak ja bym kombinował tak, że wątek ma posiadać konstruktor, do którego przekazujesz wszystkie parametry tego zdarzenia IdHTTPServer1CommandGet. Tylko kwestia jest tego Response. Spróbuj zrobić po utworzeniu wątku w IdHTTPServer1CommandGet dać na praykłąd while not MojWatek.Terminated do Application.ProcessMessages;. A po tym zwróć AResponseInfo.

Więcej pewnie doradzą lepiej Tobie inni na tym forum, gdyż ja od dawna Indy nie używam i używać za bardzo nie mam zamiaru. Także nie mam jak przetestować.

0

Problem w tym że IdHTTPServer1CommandGet wywoła się niezależnie od tego czy skończy się wykonywać kod w nim zawarty czy nie jako kolejna instancja.

`zamiana znacznika na ``` - @furious programming

2

Z tego co kojarzę to TIdHttpServer domyślnie jest wielowątkowy. Błędy, które zauważasz mogą wynikać z odwoływania się do komponentów lub innych obiektów/danych bez jakiejkolwiek synchronizacji. VCL nie jest przystosowany do pracy wielowątkowej, więc każde odwołanie do wizualnego komponentu z poziomu innego wątku powinno być synchronizowane z wątkiem głównym. Niestety dodanie synchronizacji spowoduje spadek wydajności, więc jeśli to możliwe trzeba tego unikać.

Jak nie masz wyjścia to do synchronizacji z wątkiem głównym możesz użyć metod Synchronize albo Queue. Do synchronizacji danych możesz skorzystać z klas TEvent / TMutex / TSemaphore / TCriticalSection / TMultiReadExclusiveWriteSynchronizer i pewnie jeszcze kilku innych.

http://docwiki.embarcadero.com/Libraries/XE7/en/System.Classes.TThread.Synchronize
http://docwiki.embarcadero.com/Libraries/XE7/en/System.Classes.TThread.Queue
http://docwiki.embarcadero.com/Libraries/XE7/en/System.SyncObjs

1

Ja tam może jestem ślepy ale nie widzę tam żadnych odwołań do VCL (z wyjątkiem Memo ale to było chyba tylko dla testu i na pewno zaraz zostało wywalone jeżeli się mylę to autora wątku można zabić) natomiast wiem że jak by nie było to tam potrzebna jest sekcja krytyczna ale do tego służy Lock i Unlock TIdHTTPSession (masz w ARequestInfo) i nie trzeba kombinować i na nowo wymyślać koła bo to już Indy ma wbudowane.

0

Dzięki tego mi brakowało w tym temacie:)

Przydała by się jeszcze jakaś kontrola Request'ów skąd przychodzą + ilość na jednostkę czasu aby móc blokować dany ip. który próbuje przeciążyć serwer.

1 użytkowników online, w tym zalogowanych: 0, gości: 1