Italian community of Lazarus and Free Pascal

Programmazione => Generale => Topic aperto da: Diego1981 - Marzo 14, 2017, 08:04:48 am

Titolo: soket e synapse
Inserito da: Diego1981 - Marzo 14, 2017, 08:04:48 am
per ricollegarmi alla discussione precedente, non capisco come mai ogni tanto ricevo un soket che non contine nulla (stringa vuota per essere chiaro) ma a cui viene assegnato il valore 4294967295

il server che attende il socket è tale e quale all'esempio http server della libreria synapse

procedure TServerThrd.Execute;
var
  ClientSock:TSocket;
begin
  with HttpServer do
    try
      CreateSocket;
      setLinger(true,10000);
      bind('0.0.0.0','7000');
      listen;
      repeat
        if terminated then break;
        if canread(1000) then
          begin
            ClientSock:=accept;
            if lastError=0 then
              TClientThrd.create(ClientSock);
          end;
      until false;
    except
      on E:Exception do
        begin
          Terminate;
          FR_Principale.MM_Log.Lines.Add(E.ClassName+' errore, messaggio server: '+E.Message);
        end;
    end;
end; 

"debuggando" dopo che avviene il fatto , alla riga " if canread(1000) then" ritorna sempre falso ed ho notato che è gia stato segnalato in rete ma non capisco come risolvere o almento gestire la situazione.

grazie
 
Titolo: Re:soket e synapse
Inserito da: Stilgar - Marzo 14, 2017, 11:03:08 am
Ciao Diego.
"TServerThrd" mi fa pensare che il "main" sia dentro un thread.

Il serverino che ho scritto ha come classe padre TCustomApplication.
Codice: [Seleziona]
  TWebApplication = class(TCustomApplication)
  private
    fContainer: TContainer;
    FPort: integer;
    FSocket: TTCPBlockSocket;
    function GetBaseDir: string;
    function GetDefaultIndex: string;
    procedure SetBaseDir(AValue: string);
    procedure SetDefaultIndex(AValue: string);
    procedure SetPort(AValue: integer);
  protected
    procedure DoRun; override;
  public
    procedure Initialize; override;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property Port: integer read FPort write SetPort;
    property BaseDir: string read GetBaseDir write SetBaseDir;
    property DefaultIndex: string read GetDefaultIndex write SetDefaultIndex;
    property Environment: TContainer read fContainer;
  end;


  TWebDelegateThread = class(TThread)

Codice: [Seleziona]
procedure TWebApplication.DoRun;
var
  ClientSock: TSocket;
begin
  with FSocket do
  begin
    CreateSocket;
    setLinger(True, 10000);
    bind('0.0.0.0', IntToStr(FPort));
    listen;
    while not Terminated do
    begin
      if canread(1000) then
      begin
        ClientSock := accept;
        if lastError = 0 then
        begin
          TWebDelegateThread.Create(ClientSock, fContainer);
        end;
      end;
    end;
  end;
end;   


Per l'index di test:
Codice: [Seleziona]
<html>
<head>
</head>
<body>
<script>
  window.open(location.href,'_blank');
</script>
</body>
</html>

Il server non ha problemi.
Il browser martella il server di richieste e ad ogni richiesta viene sganciato un thread, questo cerca il file e lo invia. Nel frattempo si fa una serie di giri mentali.

La differenza, credo, sta nel fatto che non apro un thread che sgancia altre thread?

Nota:
Sono partito dall'esempio che menzionavi. Forse è il test che è faccio a non essere così stressante come il tuo.

Stilgar
Titolo: Re:soket e synapse
Inserito da: Diego1981 - Marzo 14, 2017, 11:14:51 am
in effetti nella form principale con il pulsante di avvio ho inserito



interface

uses
  Classes, SysUtils, FileUtil,....,....,....,ThrdServer;

FR_Principale = class(TForm)
 ....
 ....
 ....
 ....
 private
    { private declarations }
    Server:TServerThrd;
  public
    { public declarations }
  end;

procedure TFR_Principale.BT_AvviaServerClick(Sender: TObject);
begin
  if Server=Nil then
    begin
      Server:=TServerThrd.Create;
      .........
    end;
end;   


ora comunque provo la tua soluzione
Titolo: Re:soket e synapse
Inserito da: Stilgar - Marzo 14, 2017, 12:43:32 pm
Prova a mettere il "main" in una applicazione console
Titolo: Re:soket e synapse
Inserito da: Diego1981 - Marzo 14, 2017, 01:32:12 pm
urca...qui la vita si complica ;D ???
Titolo: Re:soket e synapse
Inserito da: Diego1981 - Marzo 15, 2017, 02:00:08 pm
Ciao Stilgar
2 cose:

dimenticavo, l'errore si presenta quando ho delle pagine html leggermente elaborate (con un logo, liste, bottoni) quando sono leggere come la pagina di index dove ci sono due righe e un logo il problema non sembra presentarsi
Titolo: Re:soket e synapse
Inserito da: Stilgar - Marzo 15, 2017, 02:02:49 pm
Si Diego. E' un frammento :) Tanto per dare l'idea ;)

A questo punto sarebbe da capire il test come lo fai... :)

Stilgar
Titolo: Re:soket e synapse
Inserito da: Diego1981 - Marzo 15, 2017, 02:07:27 pm
apro 3 o 4 client su un paio di pc e faccio click nella stessa pagina HTML contemporaneamente su entrambi, a volte va e la maggior parte delle volte volte no
Titolo: Re:soket e synapse
Inserito da: Stilgar - Marzo 15, 2017, 02:10:58 pm
Quindi non ti sei scritto un programmino/script per bombardare il server...
Titolo: Re:soket e synapse
Inserito da: Diego1981 - Marzo 15, 2017, 02:13:28 pm
visto che con un paio di client va in crisi penso che un programmino sarebbe devastante
ti allego lo stamp di quello che accade quando succede l'errore
ad ogni execute del tread del client riporto il n di socket
Titolo: Re:soket e synapse
Inserito da: Stilgar - Marzo 15, 2017, 02:38:58 pm
Ciao Diego.
Ti ho mandato per mail il progetto.
Vedi se ti funziona. :)
Così mi verifichi la connessione multi pc :p

Stilgar
Titolo: Re:soket e synapse
Inserito da: Diego1981 - Marzo 15, 2017, 02:48:08 pm
intanto grazie
cerco di provare in giornata e ti faccio sapere
Titolo: Re:soket e synapse
Inserito da: Stilgar - Marzo 15, 2017, 02:59:03 pm
Occhio che la demo index.html fa impallare i browser con continue aperture di tab nuovi. :)
Uomo avvisato ... ;)

Stilgar
Titolo: Re:soket e synapse
Inserito da: Stilgar - Marzo 15, 2017, 04:26:12 pm
Ciao
Piccolo eseguibile che scarica 100 thread alla ricerca di una pagina.
Giusto per vedere se crolla il serverino ;)
Codice: [Seleziona]
program StressTest;

{$mode objfpc}{$H+}

uses {$IFDEF UNIX} {$IFDEF UseCThreads}
  cthreads, {$ENDIF} {$ENDIF}
  Classes,
  CustApp,
  httpsend,
  SysUtils;

type

  { TConnectionThread }

  TConnectionThread = class(TThread)
    procedure Execute; override;
  end;

  { TStressTest }

  TStressTest = class(TCustomApplication)
  protected
    FClients: array[0..99] of TConnectionThread;
    procedure DoRun; override;
  public
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
    procedure WriteHelp; virtual;
  end;

  { TConnectionThread }

  procedure TConnectionThread.Execute;
  var
    r: TStringList;
  begin
    r := TStringList.Create;
    Write('Server response');
    Writeln(HttpGetText('http://localhost:8081', r));
    r.Free;
    Terminate;
  end;

  { TStressTest }

  procedure TStressTest.DoRun;
  var
    t: TConnectionThread;
  begin
    Writeln('Executing ', Length(FClients), ' Connection Request');
    for t in FClients do
    begin
      t.Start;
    end;
    Writeln('Done ', Length(FClients), ' Connection Request');
    Terminate;
  end;


  constructor TStressTest.Create(TheOwner: TComponent);
  var
    t: TConnectionThread;
    i: integer;
  begin
    inherited Create(TheOwner);
    StopOnException := True;
    for i := Low(FClients) to High(FClients) do
    begin
      T := TConnectionThread.Create(True);
      FClients[i] := T;
    end;
    Writeln('Prepared ', Length(FClients), ' connection client for test');
  end;

  destructor TStressTest.Destroy;
  var
    T: TConnectionThread;
  begin
    for t in FClients do
    begin
      t.Free;
    end;
    inherited Destroy;
  end;

  procedure TStressTest.WriteHelp;
  begin
    { add your help code here }
    writeln('Usage: ', ExeName, ' -h');
  end;

var
  Application: TStressTest;

begin
  Application := TStressTest.Create(nil);
  Application.Initialize;
  Application.Title := 'ServerStressTest';
  Application.Run;
  Application.Free;
end.
Titolo: Re:soket e synapse
Inserito da: Stilgar - Marzo 15, 2017, 06:56:36 pm
Facciamo un pochino in conti :
Codice: [Seleziona]
program StressTest;

{$mode objfpc}{$H+}

uses {$IFDEF UNIX} {$IFDEF UseCThreads}
  cthreads, {$ENDIF} {$ENDIF}
  Classes,
  CustApp,
  httpsend,
  SysUtils;

type
  TTestCallback = procedure(Result: boolean) of object;
  { TConnectionThread }

  TConnectionThread = class(TThread)
  private
    FTestCallback: TTestCallback;
    FUrl: string;
    procedure SetTestCallback(AValue: TTestCallback);
    procedure SetUrl(AValue: string);
  public
    procedure Execute; override;
    property TestCallback: TTestCallback read FTestCallback write SetTestCallback;
    property Url: string read FUrl write SetUrl;
  end;

  { TStressTest }

  TStressTest = class(TCustomApplication)
  protected
    FTestCount: integer;
    FClients: array[0..99] of TConnectionThread;
    procedure DoRun; override;
    procedure TestCallback(Result: boolean);
  public
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
    procedure WriteHelp; virtual;
  end;

  { TConnectionThread }

  procedure TConnectionThread.Execute;
  var
    r: TStringList;
  begin
    r := TStringList.Create;
    if Assigned(FTestCallback) then
    begin
      FTestCallback(HttpGetText(FUrl, r));
    end
    else
    begin
      HttpGetText(FUrl, r);
    end;
    r.Free;
    Terminate;
  end;

  procedure TConnectionThread.SetTestCallback(AValue: TTestCallback);
  begin
    if FTestCallback = AValue then
    begin
      Exit;
    end;
    FTestCallback := AValue;
  end;

  procedure TConnectionThread.SetUrl(AValue: string);
  begin
    if FUrl = AValue then
    begin
      Exit;
    end;
    FUrl := AValue;
  end;

  { TStressTest }

  procedure TStressTest.DoRun;
  var
    t: TConnectionThread;
    testUrl: string;
  begin
    testUrl := 'http://localhost:8081';
    if ParamCount > 0 then
    begin
      testUrl := Params[1];
    end;
    for t in FClients do
    begin
      t.Url := testUrl;
      t.TestCallback := @TestCallback;
    end;
    Writeln('Executing ', Length(FClients), ' Connection Request');
    for t in FClients do
    begin
      t.Start;
    end;
    Writeln('Done ', Length(FClients), ' Connection Request');
    Terminate;
  end;

  procedure TStressTest.TestCallback(Result: boolean);
  var
    cs: TRTLCriticalSection;
  begin
    TryEnterCriticalsection(cs);
    if (Result) then
    begin
      Inc(FTestCount);
      Writeln('Completed test ok: ', FTestCount);
    end;
    LeaveCriticalsection(cs);
  end;


  constructor TStressTest.Create(TheOwner: TComponent);
  var
    t: TConnectionThread;
    i: integer;
  begin
    inherited Create(TheOwner);
    StopOnException := True;
    for i := Low(FClients) to High(FClients) do
    begin
      T := TConnectionThread.Create(True);
      FClients[i] := T;
    end;
    Writeln('Prepared ', Length(FClients), ' connection client for test');
  end;

  destructor TStressTest.Destroy;
  var
    T: TConnectionThread;
  begin
    for t in FClients do
    begin
      t.Free;
    end;
    inherited Destroy;
  end;

  procedure TStressTest.WriteHelp;
  begin
    { add your help code here }
    writeln('Usage: ', ExeName, ' -h');
  end;

var
  Application: TStressTest;

begin
  Application := TStressTest.Create(nil);
  Application.Initialize;
  Application.Title := 'ServerStressTest';
  Application.Run;
  Application.Free;
end.
Titolo: Re:soket e synapse
Inserito da: Diego1981 - Marzo 16, 2017, 08:47:15 am
ciao stilgar
nel lanciare il programma non mi trova le unit

slim.webapplication,
  slim.uri,
  slim.http.protocol,
  utils.php,
  psr.httpmessages,
  slim.httpmessages;

SlimServer.lpr(6,3) Fatal: Impossibile trovare la unit slim usato da SlimServer dell'Analizzatore Progetti.
Titolo: Re:soket e synapse
Inserito da: Stilgar - Marzo 16, 2017, 08:53:26 am
Strano.
Nello zip c'è tutto
Titolo: Re:soket e synapse
Inserito da: Diego1981 - Marzo 16, 2017, 10:00:30 am
infatti i file ci sono ma forse è il mio compilatore che non va a pescarli correttamente
Titolo: Re:soket e synapse
Inserito da: Stilgar - Marzo 16, 2017, 01:13:28 pm
Controlla le impostazioni del progetto.
Deve cercare i .pas dentro "../src"
Titolo: Re:soket e synapse
Inserito da: Diego1981 - Marzo 16, 2017, 01:22:12 pm
il file lpi è cosi

program SlimServer;

{$R *.res}

uses
  slim.webapplication,
  slim.uri,
  slim.http.protocol,
  utils.php,
  psr.httpmessages,
  slim.httpmessages;

begin
  Application.Initialize;
  Application.BaseDir := '..' + DirectorySeparator + '..' + DirectorySeparator + 'htdocs';
  Application.Run;
end.

nelle opzioni dei percorsi del complilatore "..\src"
nel dubbio allego stamp
Titolo: Re:soket e synapse
Inserito da: Stilgar - Marzo 16, 2017, 01:30:11 pm
Sembra tutto corretto
Titolo: Re:soket e synapse
Inserito da: Diego1981 - Marzo 16, 2017, 11:00:11 pm
non sono riuscito ad usare il tuo programma ma ho provato comunque lo stresstest e con quello nessun problema,regge tutto
potrebbe essere qualcosa nelle pagine html???
Titolo: Re:soket e synapse
Inserito da: Diego1981 - Marzo 25, 2017, 05:20:15 pm
Ciao Stilgar
scusa se mi rifaccio vivo solo adesso ma il lavoro ha interrotto i "lavori" ;D
sono riuscito a capire che l'errore che fa si che la funzione canread(1000) si metta a restituire sempre falso è il 10093 (winsock not initialized)
grazie
Titolo: Re:soket e synapse
Inserito da: Stilgar - Marzo 25, 2017, 09:46:18 pm
Bene se hai capito il problema. Ora resta da trovare una soluzione 😊
Titolo: Re:soket e synapse
Inserito da: Diego1981 - Marzo 26, 2017, 07:42:36 am
giusto  ;) :D ;D
ci provo!!
Titolo: Re:soket e synapse
Inserito da: Diego1981 - Marzo 28, 2017, 08:33:49 am
ciao Stilgar
sono riuscito a far si che l'errore non si ripeta

questo era il codice che dava l'errore quando il server veniva "martellato" da più client contemporaneamente

procedure TServerThrd.Execute;
var
  ClientSock:TSocket;
begin
  with HttpServer do
    try
      CreateSocket;
      setLinger(true,10000);
      bind('0.0.0.0','7000');
      listen;
      repeat
        if terminated then break;
        if canread(1000) then
          begin
            ClientSock:=accept;
            if lastError=0 then
              TClientThrd.create(ClientSock);
          end;
      until false;
    except
      on E:Exception do
        begin
          Terminate;
          FR_Principale.MM_Log.Lines.Add(E.ClassName+' errore, messaggio server: '+E.Message);
        end;
    end;
end; 

e questo è il codice che non mi da più l'errore

procedure TServerThrd.Execute;
var
  ClientSock:TSocket;
  ThrdClient:TClientThrd;
begin
  with HttpServer do
    try
      CreateSocket;
      RaiseExcept:=True;
      setLinger(true,10000);
      bind('0.0.0.0','7000');
      listen;
      while not Terminated do
        begin
          if canread(1000) then
            begin
              ClientSock:=accept;
              if lastError=0 then
                begin
                  ThrdClient:=TClientThrd.Create(ClientSock);  //RIGA INCRIMINATA ;D
                end;
            end;
        end;
    except
      on E:Exception do
        begin
          Free;
          FR_Principale.MM_Log.Lines.Add(E.ClassName+' errore, messaggio server: '+E.Message);
        end;
    end;

A livello teorico non capisco esattamente cosa cambia, puoi darmi la dritta?

grazie