Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Internet (https://www.clubdelphi.com/foros/forumdisplay.php?f=3)
-   -   Datos personalizados en los Context de la Indy (https://www.clubdelphi.com/foros/showthread.php?t=69014)

fide_uci 20-07-2010 23:26:59

Datos personalizados en los Context de la Indy
 
Hola amigos de clubdelphi. Quiciera comentarles que me encuentro desarrollando un juego en flash y dado que es multiplayer he tenido que tomar a delphi + indy como las opciones para crear un servidor para la aplicacion.

Todo funciona bien. Pero el problema es que por cada conexion que se crea, tengo que tener una cantidad de datos que me hacen falta y todo ello lo guardo en un puntero a un objeto que me dan los context de la Indy. O sea asi de esta manera.

Código Delphi [-]
(****************************************************************
  Declaracion del tipo TCliente para agregar otros datos a los
  Context de la Indy.
****************************************************************)

type TClient = record
 Host         : String[255]; // Guarda el IP de cada cliente
 Hora_Login   : String[255]; // Guarda la hora en la que se logueo el cliente
 Thread       : Pointer;
end;

type PClient   = ^TClient;

(****************************************************************)


//Aqui asigno los valores a las variables.
procedure TForm1.TCPServerConnect(AContext: TIdContext);
var
  NewClient: PClient;
begin
  GetMem(NewClient, SizeOf(TClient));

  NewClient.Host        := AContext.Connection.Socket.Binding.PeerIP;
  NewClient.Hora_Login  := FormatDateTime('hh:mm:ss - dd/mm/yyyy', Now);
//  NewClient.Thread      := AContext;

  TIdContext(TCPServer.Contexts.LockList.Items[TCPServer.Contexts.LockList.Count -1]).Data := TObject(NewClient);
  TCPServer.Contexts.UnlockList;

  Memo1.Lines.Add('Alguien se ha conectado desde: ' + PClient(AContext.Data).Host );
  Memo1.Lines.Add('y en fecha/hora: ' + PClient(AContext.Data).Hora_Login );
  Memo1.Lines.Add(DupeString('-', 50));
  //FreeMem(NewClient);

end;
Esto me funciona bien, pero cuando conecto otro cliente me comienza a dar errores y se me conjela la app pincipal que tengo que tumbarla de los procesos. Alguien sabe como puedo hacer eso que quiero de la forma correcta ?. Aqui pongo toda la unit para que se entienda mas !!!

Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection,
  IdTCPClient, IdIntercept, IdIOHandler, IdIOHandlerStream, xmldom,
  XMLIntf, msxmldom, XMLDoc, xercesxmldom, oxmldom, IdIOHandlerSocket,
  IdIOHandlerStack, IdSSL, IdSSLOpenSSL, JvSimpleXml, JvExControls,
  JvEditorCommon, JvUnicodeEditor, JvExStdCtrls, JvRichEdit,
  JvUnicodeHLEditor, JvHLEditorPropertyForm, ImgList, ComCtrls, ExtCtrls,
  XPMan, ToolWin, Menus, XPStyleActnCtrls, ActnList, ActnMan,
  IdUserPassProvider, IdSASL, IdSASLUserPass, IdSASLDigest, JvExExtCtrls,
  JvExtComponent, JvRollOut, JvWizard, Sockets, AdvShapeButton, IdContext,
  IdCustomTCPServer, IdTCPServer;

(****************************************************************
  Declaracion del tipo TCliente para agregar otros datos a los
  Context de la Indy.
****************************************************************)

type TClient = record
 Host         : String[255]; // Guarda el IP de cada cliente
 Hora_Login   : String[255]; // Guarda la hora en la que se logueo el cliente
 Thread       : Pointer;
end;

type PClient   = ^TClient;

(****************************************************************)


type
  TForm1 = class(TForm)
    StatusBar1: TStatusBar;
    Panel2: TPanel;
    Panel3: TPanel;
    Memo1: TMemo;
    TCPServer: TIdTCPServer;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Timer1: TTimer;
    procedure TCPServerConnect(AContext: TIdContext);
    procedure TCPServerExecute(AContext: TIdContext);
    procedure Button1Click(Sender: TObject);
    procedure TCPServerDisconnect(AContext: TIdContext);
    procedure Button2Click(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure Button3Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;


var
  Form1     :TForm1;
  //Clients  :TThreadList;


implementation

{$R *.dfm}


uses StrUtils, IdBuffer, unConfigCon, IdTask;

procedure TForm1.TCPServerConnect(AContext: TIdContext);
var
  NewClient: PClient;
begin
  GetMem(NewClient, SizeOf(TClient));

  NewClient.Host        := AContext.Connection.Socket.Binding.PeerIP;
  NewClient.Hora_Login  := FormatDateTime('hh:mm:ss - dd/mm/yyyy', Now);
//  NewClient.Thread      := AContext;

  TIdContext(TCPServer.Contexts.LockList.Items[TCPServer.Contexts.LockList.Count -1]).Data := TObject(NewClient);
  TCPServer.Contexts.UnlockList;

  Memo1.Lines.Add('Alguien se ha conectado desde: ' + PClient(AContext.Data).Host );
  Memo1.Lines.Add('y en fecha/hora: ' + PClient(AContext.Data).Hora_Login );
  Memo1.Lines.Add(DupeString('-', 50));
  //FreeMem(NewClient);

end;

procedure TForm1.TCPServerExecute(AContext: TIdContext);
var
  dato: String;
  vIP: String;
  List: TList;
  vCount: Integer;
begin

  dato := AContext.Connection.Socket.ReadLn();
  Memo1.Lines.Add(#13 + DupeString('=', 30));
  Memo1.Lines.Add('Hora_Login: ' + PClient(AContext.Data).Hora_Login );
  Memo1.Lines.Add('Enviado: ' + dato);
  //AContext.Connection.Socket.WriteLn('Algo aqui !');

  List := TCPServer.Contexts.LockList;

  try
    for vCount := 0 to List.Count -1 do
    try
      vIP := PClient(TIdContext(List.Items[vCount]).Data).Host;
      TIdContext(List.Items[vCount]).Connection.Socket.WriteLn(vIP + ': ' + dato);
    except
      //TIdContext(List.Items[Count]).Stop;
    end;
  finally
    TCPServer.Contexts.UnlockList;
  end;


end;

procedure TForm1.Button1Click(Sender: TObject);
begin

  TCPServer.Active := False;
  TCPServer.Active := True;

end;

procedure TForm1.TCPServerDisconnect(AContext: TIdContext);
begin

  AContext.Data := nil;

end;

procedure TForm1.Button2Click(Sender: TObject);
var
  List: TList;
  Count: Integer;
  vDatos: PClient;
begin

  //Memo1.Lines.Add('Hora_Login: ' + PClient(AContext.Data).Hora_Login );
// GetMem(vDatos, SizeOf(TClient));

 List := TCPServer.Contexts.LockList;
  try
    for Count := 0 to List.Count -1 do
    try
      //TIdContext(List.Items[Count]).Connection.Socket.WriteLn('Locas');
      vDatos := PClient( TIdContext(List.Items[Count]).Data);
      Memo1.Lines.Add('Hora Login: ' + vDatos.Hora_Login);
    except
    end;
  finally
    TCPServer.Contexts.UnlockList;
  end;

end;

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin

  TCPServer.StopListening;
  TCPServer.Active := False;

end;

procedure TForm1.Button3Click(Sender: TObject);
var
  List: TList;
  Count: Integer;
begin

  List := TCPServer.Contexts.LockList;

  try
    for Count := 0 to List.Count -1 do
    try
      TIdContext(List.Items[Count]).Connection.Disconnect(True);
    except
      //TIdContext(List.Items[Count]).Stop;
    end;
  finally
    TCPServer.Contexts.UnlockList;
  end;

end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin

//  Caption := IntToStr(TCPServer.Contexts.LockList.Count);
//  TCPServer.Contexts.UnlockList;

end;

end.

manuc 23-07-2010 17:31:27

Hola fide_uci,

Creo que uno de los problemas puede estar aquí:
Código Delphi [-]
procedure TForm1.TCPServerExecute(AContext: TIdContext);
var
  dato: String;
  vIP: String;
  List: TList;
  vCount: Integer;
begin

  dato := AContext.Connection.Socket.ReadLn();
  Memo1.Lines.Add(#13 + DupeString('=', 30));
  Memo1.Lines.Add('Hora_Login: ' + PClient(AContext.Data).Hora_Login );
  Memo1.Lines.Add('Enviado: ' + dato);
  //AContext.Connection.Socket.WriteLn('Algo aqui !');

Ten en cuenta que el evento onExecute se dispara cada vez que un hilo tiene actividad, y es un sistema multi-hilos, es decir, más de un hilo puede estar disparándolo al mismo tiempo.

Dentro de este tipo de métodos, no puedes hacer referencias a componentes VCL directamente, sino, que tienes que hacerlo a través de métodos compartidos y llamarlos con "Synchronize", para que cuando se acceda a la VCL, se haga de modo "ordenado".

Precisamente, cuando hay conflicto de acceso a VCL en este tipo de métodos la aplicación se congela.

Espero que te ayude.

Un saludo.

fide_uci 24-07-2010 03:04:59

Hmm ya voy entiendiendo. Pero bueno mi error no era debido a lo de el acceso a la VCL sino a otra cosa. Es que estaba liberando un puntero y por eso me estaba dando errores. Muchas gracias por tu ayuda !

fide_uci 24-07-2010 03:10:03

O sea mas concretamente el error estaba en que sin darme cuenta estaba Bloqueando 2 veces la lista en la misma linea y por eso me explotaba.

Código Delphi [-]
 TIdContext(TCPServer.Contexts.LockList.Items[TCPServer.Contexts.LockList.Count -1]).Data := TObject(NewClient);
Cuando en realidad la forma correcta seria meter el LockList es una variable de tipo TList para poder acceder a ella mas o menos de esta forma.

Código Delphi [-]
...
var
   vLista: TList;
begin
   vLista := TCPServer.Contexts.LockList;
end;


La franja horaria es GMT +2. Ahora son las 10:14:16.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi