Newsgroup: it.comp.lang.delphi
Titolo: Client/Server/Client part2

Salve ragazzi qualche tempo fa ho postato una richiesta di aiuto per
realizzare un' applicazione client server che deviasse il flusso
entrante su una porta diversa rispetto a quella di entrate.
Andrea mi ha consigliato questo codice:
Il codice del server:
unit Unit1;
interface
uses
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms,
   Dialogs, IdBaseComponent, IdComponent, IdTCPServer, StdCtrls;
type
   TForm1 = class(TForm)
     Button1: TButton;
     IdTCPServer1: TIdTCPServer;
     Memo1: TMemo;
     procedure FormCreate(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
     procedure IdTCPServer1Execute(AThread: TIdPeerThread);
     procedure IdTCPServer1Connect(AThread: TIdPeerThread);
     procedure IdTCPServer1Disconnect(AThread: TIdPeerThread);
   private
     FOutputThread: TIdPeerThread;
   public
   end;
var
   Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
   FOutputThread := nil;
   IdTCPServer1.Bindings.Add.Port := 55555; // porta con connessioni in
entrata
   IdTCPServer1.Bindings.Add.Port := 55556; // porta con connessioni in
uscita
   IdTCPServer1.Active := True;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
   IdTCPServer1.Active := False;
end;
procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var
   DataSize: Cardinal;
   DataStream: TMemoryStream;
begin
   try
     if Assigned(AThread) and AThread.Connection.Connected then
     begin
       if AThread.Connection.Socket.Binding.Port = 55556 then
         Sleep(100) // ignoriamo qualsiasi cosa arrivi dalla porta
55556
       else
       begin
         DataSize := AThread.Connection.ReadCardinal;
         Memo1.Lines.Add(Format('DataSize read: %d', [DataSize]));
         if DataSize>0 then
         begin
           DataStream := TMemoryStream.Create;
           try
             AThread.Connection.ReadStream(DataStream, DataSize);
             if Assigned(FOutputThread) and
FOutputThread.Connection.Connected then
             begin
               FOutputThread.Connection.WriteCardinal(DataSize);
               DataStream.Position := 0;
               FOutputThread.Connection.WriteStream(DataStream);
             end;
           finally
             DataStream.Free;
           end;
         end;
       end;
     end;
   except
     on E: Exception do
     begin
       Application.MessageBox(PChar(Format('%s.%s(): %s', [ClassName,
'IdTCPServer1Execute', E.Message])),
                              'Attenzione', MB_ICONWARNING+MB_OK);
       if Assigned(AThread) then
         AThread.Connection.Disconnect;
       if Assigned(FOutputThread) then
       begin
         FOutputThread.Connection.Disconnect;
         FOutputThread := nil;
       end;
     end;
   end;
end;
procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);
begin
   Memo1.Lines.Add(Format('client connected on port: %d',
[AThread.Connection.Socket.Binding.Port]));
   if AThread.Connection.Socket.Binding.Port = 55556 then
   begin
     if Assigned(FOutputThread) then AThread.Connection.Disconnect
     else
       FOutputThread := AThread;
   end;
end;
procedure TForm1.IdTCPServer1Disconnect(AThread: TIdPeerThread);
begin
   Memo1.Lines.Add(Format('client disconnected on port: %d',
[AThread.Connection.Socket.Binding.Port]));
   if AThread = FOutputThread then
     FOutputThread := nil;
end;
Il codice del client:
unit Unit1;
interface
uses
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms,
   Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
   StdCtrls;
type
   TClientThreadErrorNotify = procedure(ASender: TObject; AErrorString:
String) of object;
   TClientThread = class(TThread)
   private
     FError: String;
     FMainFormHandle: HWND;
     FCleanDisconnect: Boolean;
     FOnError: TClientThreadErrorNotify;
     FIdTCPClient: TIdTCPClient;
     function GetHost: string;
     procedure SyncException;
   protected
     procedure Execute; override;
     procedure Operation(AStream: TStream); virtual;
     procedure OnThTerminate(ASender: TObject);
   public
     constructor Create; reintroduce; virtual;
     destructor Destroy; override;
     procedure Open(AMainFormHandle: HWND; AHost: String;
APort:Integer;
AResume: Boolean); virtual;
     procedure Close; virtual;
     property OnError: TClientThreadErrorNotify read FOnError write
FOnError;
     property Host:String read GetHost;
   end;
type
   TForm1 = class(TForm)
     Memo1: TMemo;
     IdTCPClient1: TIdTCPClient;
     Memo2: TMemo;
     btnDisconnectAll: TButton;
     Button1: TButton;
     procedure FormCreate(Sender: TObject);
     procedure ClientConnectedEvent(Sender: TObject);
     procedure ClientDisconnectedEvent(Sender: TObject);
     procedure btnDisconnectAllClick(Sender: TObject);
     procedure Button1Click(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
     procedure WMStartReceivedData(var Msg: TMessage); message
WM_USER+100;
     procedure WMWriteReceivedData(var Msg: TMessage); message
WM_USER+101;
     procedure WMEndReceivedData(var Msg: TMessage); message
WM_USER+102;
   private
     FClientThread: TClientThread;
   public
     { Public declarations }
   end;
var
   Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.ClientConnectedEvent(Sender: TObject);
begin
   TMemo((Sender as TIdTCPClient).Tag).Lines.Add('Connesso!');
end;
procedure TForm1.ClientDisconnectedEvent(Sender: TObject);
begin
   TMemo((Sender as TIdTCPClient).Tag).Lines.Add('Disconnesso!');
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
   Randomize;
   IdTCPClient1.Port := 55555;
   IdTCPClient1.Host := '127.0.0.1';
   IdTCPClient1.Tag := Integer(Memo1);
   IdTCPClient1.Connect;
   FClientThread := TClientThread.Create;
   FClientThread.Open(Self.Handle, '127.0.0.1', 55556, True);
end;
procedure TForm1.btnDisconnectAllClick(Sender: TObject);
begin
   IdTCPClient1.Disconnect;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
   I, N, Num: Cardinal;
   DataSize: Cardinal;
   DataStream: TMemoryStream;
begin
   N := Random(5)+1;
   DataSize := N * Sizeof(N);
   DataStream := TMemoryStream.Create;
   try
     IdTCPClient1.WriteCardinal(DataSize);
     Memo1.Lines.Add('Stream data written: ---- start');
     for I := 1 to N do
     begin
       Num := Random(2000)+100;
       Memo1.Lines.Add(IntToStr(Num));
       DataStream.WriteBuffer(Num, SizeOf(Num));
     end;
     Memo1.Lines.Add('Stream data written: ---- end');
     IdTCPClient1.WriteStream(DataStream);
   finally
     DataStream.Free;
   end;
end;
{ TClientThread }
procedure TClientThread.Close;
begin
   FCleanDisconnect := True;
   if not Terminated then
     Terminate;
   if Assigned(FIdTCPClient) then
   begin
     if FIdTCPClient.Connected then
       FIdTCPClient.Disconnect;
   end;
   Free;
end;
constructor TClientThread.Create;
begin
   inherited Create(True);
   FCleanDisconnect := False;
   OnTerminate := OnThTerminate;
end;
destructor TClientThread.Destroy;
begin
   inherited;
end;
procedure TClientThread.Execute;
var
   DataSize: Cardinal;
   DataStream: TMemoryStream;
begin
   while not Terminated do
   begin
     if FIdTCPClient.Connected then
     begin
       try
         DataSize := FIdTCPClient.ReadCardinal;
         DataStream := TMemoryStream.Create;
         try
           if DataSize>0 then
             FIdTCPClient.ReadStream(DataStream, DataSize);
           Operation(DataStream);
         finally
           DataStream.Free;
         end;
       except
         on E:Exception do
           FIdTCPClient.Disconnect;
       end;
     end
     else
     begin
       if not FCleanDisconnect then
       begin
         FError := 'Connection with server lost!';
         Synchronize(SyncException);
       end;
       Terminate;
     end;
   end;
end;
function TClientThread.GetHost: string;
begin
   Result := FIdTCPClient.Host;
end;
procedure TClientThread.OnThTerminate(ASender: TObject);
begin
   if Assigned(FIdTCPClient) then
   begin
     FIdTCPClient.Free;
     FIdTCPClient := nil;
   end;
end;
procedure TClientThread.Open;
begin
   FMainFormHandle := AMainFormHandle;
   FIdTCPClient := TIdTCPClient.Create(nil);
   FIdTCPClient.Host := AHost;
   FIdTCPClient.Port := APort;
   FIdTCPClient.Connect;
   if AResume then Resume;
end;
procedure TClientThread.SyncException;
begin
   if Assigned(FOnError) then
     FOnError(Self, FError);
end;
procedure TClientThread.Operation;
var
   N: Cardinal;
begin
   PostMessage(FMainFormHandle, WM_USER+100, N, 0);
   AStream.Position := 0;
   while AStream.Read(N, SizeOf(N))>0 do
     PostMessage(FMainFormHandle, WM_USER+101, N, 0);
   PostMessage(FMainFormHandle, WM_USER+102, N, 0);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
   FClientThread.Free;
end;
procedure TForm1.WMEndReceivedData(var Msg: TMessage);
begin
   Memo2.Lines.Add('Stream data read: ---- start');
end;
procedure TForm1.WMStartReceivedData(var Msg: TMessage);
begin
   Memo2.Lines.Add('Stream data read: ---- end');
end;
procedure TForm1.WMWriteReceivedData(var Msg: TMessage);
begin
   Memo2.Lines.Add(IntToStr(Msg.WParam));
end;
end.
end.
Questo funziona correttamente solo che il client connesso alla porta
55555 invia il flusso e il 55556 riceve sempre.
Io dovrei farlo dinamico nel senso che entrambi i client possono
mandare e ricevere il flusso.
Qualche idea?



 55555 invia il flusso e il 55556 riceve sempre.
Sull'OnExecute del server, se guardi bene il mio codice, viene ignorata 
qualsiasi cosa arrivi dai socket connessi alla 55556.  Ti basta 
implementare la lettura e la scrittura verso la connessione sulla porta 
55555.  Il codice ce l'hai già.

Ti dico quello che ho fatto, per qunato riguarda il client l'ho
suddiviso in due form distinti, uno che lavora solo con la classe creta
da te, nell'altro ho rimplementato la procedura onexcute ma nn so dove
richiamarla.....per quanto riguarda il server nn devo anche modificare
l'evento onConnect perche altrimenti il thread d'uscita sara sempre
relativo alla porta 55556? Questa assegnazione nn andrebbe messa
nell'evento onexcute del server?

Qualche idea?
penso che basti dotare il server di un client ed il
client di un server con porte reciproche, in maniera da
lasciare le sue logiche separate ma dare la
possibilitą ad entrambi di trasmettere e ricevere.
	Ciao
	MassimoB
 
---------------------------------
http://www.massimobeschi.it/
---------------------------------
Se tu pagare come dici tu ...
Io lavorare come dico io ...
Se tu pagare come dico io ...
Io lavorare come dici tu ...
---------------------------------