Fórum AThread #308767

11/01/2006

0

Eu estou usando os componentes idTCPServer e idTCPCliente.

Para armazenar os AThread dos clientes e algumas informacoes sobre ele fiz o seguinte:

  PPc = ^TPc;
TPc = Record
Thread: TIdPeerThread;
Ip: String;
Cliente: String;
ClienteN: Integer;
Pc: Integer;


Dentro de PPc eu coloco as informações e o AThread quando conecta, e guardo no TList

O problema é que quando ele conecta da um erro doido e ele da erro na hora de colocar o AThread, já fiz de tudo mas nada resolve o problema.

E fiz praticamente igual ao do exemplo do Indy e mesmo assim não funciona.

Alguem pode me ajudar??


Rudá

Rudá

Responder

Posts

11/01/2006

Massuda

Talvez você devesse dar uma olhada no exemplo IdTCPDemo. Note que os dados dos clientes são guardados numa TThreadList, que é uma lista thread safe; um TList não serve porque podem ocorrer problemas de sincronismo durante a execução.

É importante lembrar que a thread/conexão do cliente pode a qualquer instante deixar de existir.

Existem outras formas de manter a lista dos clientes conectados, mas isso depende do que você pretende fazer.


Responder

Gostei + 0

11/01/2006

Rudá

E aonde baixo esse Demo??


Responder

Gostei + 0

11/01/2006

Massuda

[url=http://www.indyproject.org/Sockets/Demos/index.en.html]Nesta página[/url] do site oficial do Indy.


Responder

Gostei + 0

11/01/2006

Rudá

Achei e testei, tudo blz o problema é quando fui dar um count, ele para de funcionar quando fecho o o cliente ele nao desconecta, e da tudo errado.

O que pode ser??


Responder

Gostei + 0

11/01/2006

Massuda

O que pode ser??
Você precisaria dar mais detalhes para ser possível dizer alguma coisa... note que não basta apenas o código, mas sim o que você está tentando fazer.


Responder

Gostei + 0

12/01/2006

Rudá

Tentei resolver, mas não consegui, agora to tentando usar array, mas da erro: [b:35ec1c308b]No execute handler found[/b:35ec1c308b]

Decclarei: [b:35ec1c308b]Thread: Array of TIdPeerThread;[/b:35ec1c308b]

E na função: [b:35ec1c308b]TCPServerConnect[/b:35ec1c308b] coloquei: [b:35ec1c308b]SetLength(Thread,1); Thread[0]:= AThread;[/b:35ec1c308b]

E na função: [b:35ec1c308b]TCPServerDisconnect[/b:35ec1c308b] coloquei: [b:35ec1c308b]Thread[0]:= nil;[/b:35ec1c308b]

Quando conecto ele da o erro.

O que pode ser???


Responder

Gostei + 0

12/01/2006

Massuda

No execute handler found
Esse ocorre porque você precisa ter pelo menos um item na lista CommandHandlers (ou estar com CommandJHandlersEnabled = False).

Decclarei: [b:b30ec0bd03]Thread: Array of TIdPeerThread;[/b:b30ec0bd03]....
Um servidor Indy trata cada cliente usando uma thread, ou seja, o servidor é multithread.

Por causa disso, qualquer código que envolva mais de um cliente (que é o caso do que você está tentando fazer) precisa ser thread-safe, ou seja, precisa ter algum mecanismo que permita compartilhamento de dados (caso do TThreadList) e/ou (se for o caso) que garanta sincronismo entre diferentes threads. O exemplo do Indy que citei num post anterior usa um TThreadList.

Pelo que você postou, o código pode eventualmente até funcionar para um único cliente, mas falhará (de modo aleatório) quando mais de um cliente se conectar ao servidor. Estude mais o exemplo que citei e implemente algo parecido.

Outra coisa... seja lá o que você pretenda fazer, não utilize a thread do cliente que você está armazenando na estrutura de dados sem antes bloquear o servidor. Normalmente, você faz isso assim...
var
  List: TList;
  Peer: TIdPeerThread;
...
  List := IdTCPServer1.Threads.LockList; //isso bloqueia o servidor!
  try
    for I := 0 to List.Count - 1 do begin
      // List[I] é uma das threads do servidor
      Peer := TIdPeerThread(List[I]);
      Peer.Connection.WriteLn(´Oi´);
    end;
  finally
    IdTCPServer1.Threads.UnlockList
  end;

Uma alternativa é você derivar uma classe de TIdPeerThread e incluir nessa classe derivada os dados que você desejar; preencha esses dados no OnConnect do servidor. Você diz ao servidor para usar sua classe ao invés de TIdPeerThread através da propriedade TIdTCPServer.ThreadClass.


Responder

Gostei + 0

12/01/2006

Rudá

OK,

Pode me ajudar, qual é a melhor opção?


Responder

Gostei + 0

12/01/2006

Rudá

Fiz esse exemplo simples e não funciona.

Server:

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, IdThreadMgr, IdThreadMgrDefault, IdBaseComponent,
  IdComponent, IdTCPServer;

type
  TForm1 = class(TForm)
    TCPServer: TIdTCPServer;
    Memo: TMemo;
    Button1: TButton;
    ThreadMgr: TIdThreadMgrDefault;
    procedure TCPServerConnect(AThread: TIdPeerThread);
    procedure FormShow(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure TCPServerDisconnect(AThread: TIdPeerThread);
  private
    { Private declarations }
  public
    Thread: TList;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormShow(Sender: TObject);
begin
TCPServer.Active:= True;
end;

procedure TForm1.TCPServerConnect(AThread: TIdPeerThread);
begin
Thread.Add(AThread);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
Memo.Lines.Clear;
for i:= 0 to Thread.Count-1 do
Memo.Lines.Add(TIdPeerThread(Thread[i]).Connection.Socket.Binding.PeerIP);
end;

procedure TForm1.TCPServerDisconnect(AThread: TIdPeerThread);
begin
Thread.Remove(AThread);
end;

end.


Cliente:

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection,
  IdTCPClient, IdAntiFreezeBase, IdAntiFreeze;

type
  TForm_Principal = class(TForm)
    TCPClient: TIdTCPClient;
    IP: TEdit;
    Button1: TButton;
    AntiFreeze: TIdAntiFreeze;
    Memo: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure TCPClientConnected(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TClientThread = class(TThread)
  protected
    procedure Execute; override;
  public
    constructor Create(CreateSuspended: Boolean);
  end;

var
  Form_Principal: TForm_Principal;

implementation

{$R *.dfm}

procedure TForm_Principal.Button1Click(Sender: TObject);
begin
TCPClient.Host:= IP.Text;
TCPClient.Connect;
end;


constructor TClientThread.Create(CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);
Priority := tpIdle;
FreeOnTerminate:= true;
end;

procedure TClientThread.Execute;
begin
inherited;
with Form_Principal do
begin
if not TCPClient.Connected then
exit;
repeat
Form_Principal.Memo.Lines.Add(TCPClient.ReadLn);
until not TCPClient.Connected;
end;
end;

procedure TForm_Principal.TCPClientConnected(Sender: TObject);
begin
TClientThread.Create(false);
end;

end.


E não funciona da um erro doido quando o cliente conecta:

Project server.exe raised exception class EAccessViolation with message ´Access violation at address 00413AEF in module ´server.exe´. Read of address ´00000008´. Process stopped. Use Step or Run to continue.

Nem sei o que pode ser, o exemplo é simples e deveria funcionar e nada de funcionar.


Responder

Gostei + 0

12/01/2006

Massuda

Sem querer ofender, numa rápida olhada, eu diria que seu código pode até funcionar, mas está errado.

Antes de prosseguir, o que você está tentando implementar?


Responder

Gostei + 0

12/01/2006

Rudá

Eu estou tentando fazer tipo um sistema de lan house.


Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar