Fórum AThread #308767
11/01/2006
0
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á
Curtir tópico
+ 0Posts
11/01/2006
Massuda
É 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.
Gostei + 0
11/01/2006
Rudá
Gostei + 0
11/01/2006
Massuda
Gostei + 0
11/01/2006
Rudá
O que pode ser??
Gostei + 0
11/01/2006
Massuda
Gostei + 0
12/01/2006
Rudá
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???
Gostei + 0
12/01/2006
Massuda
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.
Gostei + 0
12/01/2006
Rudá
Pode me ajudar, qual é a melhor opção?
Gostei + 0
12/01/2006
Rudá
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.
Gostei + 0
12/01/2006
Massuda
Antes de prosseguir, o que você está tentando implementar?
Gostei + 0
12/01/2006
Rudá
Gostei + 0
Clique aqui para fazer login e interagir na Comunidade :)