Array
(
)

idTcpClient pode ficar escutando os comandos do idTcpServer?

Paullsoftware
   - 20 mar 2006

Ai pessoal, pelo que entendi os componentes indy funcionam em um meio de pergunta e resposta, certo?

O cliente faz uma pergunta o servidor responde, o servidor faz uma pergunta o cliente responde e assim por diante. Se o cliente fizer mais de uma pergunta por vez o servidor enviará uma reposta de cada vez até por que será feita uma resposta por vez:
#Código


IdTcpClient.WriteLn(‘#Comando’);
ShowMessage(idTcpClient.ReadLn());


Minha dúvida é a seguinte: Se eu quiser enviar um comando do cliente para o servidor basta colocar um botão e fazer:
#Código

idClient.WriteLn(‘HORA’); //um exemplo para pedir a hora do servidor
MsgResposta := idClient.ReadLn();//Aqui já pego a resposta do servidor, certo?

:arrow: :arrow: No servidor coloco no evento OnTcpServerExecute;
#Código

Var
Msg : String;
Begin
Msg := UpperCase(idTcpServer.ReanLn());
If Msg = ‘#HORA’ then // se o cliente estiver pedindo a hora envio para ele uma resposta...
idTcpServer.WriteLn(Time);


Resumindo, sabemos que para ler as solicitações do cliente basta colocar uma instrução neste evento no servidor, certo? Mais e no cliente, como faço para aguardar os comandos do servidor. Tentei colocar um timer para ficar assim: :idea: :idea: :idea:
#Código

var
msg : String;
begin
msg := ´´;
if IdTCPClient.Connected then
begin
msg := IdTCPClient.ReadLn();
if msg <>´´ then
begin
ListBox1.Items.Add(msg);
end
else
begin
Exit;
end;
end;
end;
só que a minha aplicação trava quando não há nenhuma mensagem vinda do servidor!... :!: :!: :!:

Minha pergunta é tem como o cliente ficar escutando os comandos do servidor, sem ser nas seqüências abaixo?
#Código

IdTcpClient.WriteLn(‘#Comando’);
ShowMessage(idTcpClient.ReadLn());

:?: :?: :?:


Massuda
   - 20 mar 2006

Talvez [url=http://forum.clubedelphi.net/viewtopic.php?t=70214]este tópico[/url] seja útil para você. Tem dois modos de resolver isso, uma é usando uma thread para o cliente ler o que chega do servidor ou você usar um TIdTCPServer também no cliente. Na versão 10 do Indy tem novos recursos para suportar isso, mas eu não conheço como usar (não uso a versão 10).


Paullsoftware
   - 20 mar 2006

Massuda, tentei implementar seu o código do Tópico que vc informou, mais não compila, dar um erro nessa linha:
#Código

type
TReadingThread = class(TThread)
protected
FConn: TIdTCPConnection;
procedure Run; override;//aqui da o erro!
public
constructor Create(AConn: TIdTCPConnection); reintroduce;
end;
TForm1 = class(TForm)
ListBox1: TListBox;
Edit1: TEdit;
Button1: TButton;
IdTCPClient: TIdTCPClient;
SpeedButton1: TSpeedButton;
Edit2: TEdit;
SpinEdit1: TSpinEdit;
...


só resaultando, copiei e colei o código para testar! :roll:


Massuda
   - 20 mar 2006

:oops: Onde está procedure Run, é procedure Execute.


Paullsoftware
   - 20 mar 2006


Citação:
:oops: Onde está procedure Run, é procedure Execute.

#Código

Reader.TerminateAndWaitFor;

aqui também é só terminate?? :?: :?:


Massuda
   - 20 mar 2006

Olhei novamente o código que está no outro tópico e percebi que a classe TReadingThread é derivada de TIdThread e não de TThread, como você fez; o código original deve funcionar se você mudar isso.

Se preferir continuar a derivar de TThread, o TIdThread.TerminateAndWaitFor corresponde a chamar TThread.Terminate seguido de TThread.WaitFor.


Paullsoftware
   - 20 mar 2006

funcinou, mais eu coloquei um timer para ficar testando a conexão assim:
#Código

if idTcpClient.Connected then
Reader := TReadingThread.Create(IdTCPClient);
setei o interval para 500, na procedure Execute coloquei para tratar os comandos que vem do servidor e se não for reconhecido to dando um Exit será que to fazendo certo :?: :?: :?:


Massuda
   - 20 mar 2006

Não entendi porque você está usando um timer. Não precisa. A thread, depois de ser criada, vai executar sempre que chegar algo do servidor e irá terminar quando houver desconexão.


Paullsoftware
   - 20 mar 2006


Citação:
Não entendi porque você está usando um timer. Não precisa. A thread, depois de ser criada, vai executar sempre que chegar algo do servidor e irá terminar quando houver desconexão.

então isso é estranho não está funcionando assim...
vou fazer mais alguns testes e post o resultado! :wink:


Paullsoftware
   - 20 mar 2006

realmente massuda a Trhade é criada, mais não esta funcionando, alias, só funciona no momento da conexão da estação com o servidor...
quando conecto a estação vem na hora a resposta do cliente:
#Código

idTcpServer.WriteLn(´Conectado com Sucesso!´);

mais depois disso se enviar algum comando do servidor não é executado, comente quando o cliente faz uma nova solicitação é mostrar a mensagem que o servidor havia enviado antes.. já quando eu coloco o timer, menseionado anteriormente funciona! o que pode ser?


Paullsoftware
   - 20 mar 2006

depois de fazer alguns testes, cheguei a esse código:
#Código

procedure TReadingThread.Execute;
var
Command: String;
begin
With fMain do
begin
if not IdTCPClient.Connected then Exit;
repeat
Command := UpperCase(FConn.ReadLn);
if Command = ´#NET´ then FConn.WriteLn(´Desconectado do Servidor´)//ShowMessage(´Desconectado do Servidor´)
else if Command = ´BLOCK´ then FConn.WriteLn(´Executado com sucesso!´)//ShowMessage(´Terminal Bloqueado´)
else if Command = ´SHUTDOWN´ then FConn.WriteLn(´Executado com sucesso!´)//ShowMessage(´Desligar Terminal´)
else if Command = ´LIBERA´ then FConn.WriteLn(´Executado com sucesso!´)//ShowMessage(´Terminal Liberado´)
else if Command = ´REBOOT´ then FConn.WriteLn(´Executado com sucesso!´)//ShowMessage(´Reiniciar Terminal´)
else if Command = ´TELA´ then FConn.WriteLn(´Executado com sucesso!´)//ShowMessage(´Enviar Tela do Terminal´)
else if Command = ´#STOP´ then FConn.WriteLn(´Executado com sucesso!´);//ShowMessage(´Parar Tempo´);
ListBox1.Items.Add(Command);
Command := ´´;
until not IdTCPClient.Connected;
end;
end;

a principio esta funcionando corretamente, mais o estranho é que quando estava usando as ShowMessages(); não estava funcionando, sabe informar pq? :?: :?: :?:


Massuda
   - 20 mar 2006


Citação:
...quando estava usando as ShowMessages(); não estava funcionando, sabe informar pq?
Porque é uma thread! Todo programa Delphi tem uma thread principal que cuida da interface com o usuário (vulgarmente, a ´tela´); qualquer outra thread que você cria e que precisa acessar a interface com o usuário precisa fazer isso de forma sincronizada (duas threads não podem usar a tela simultaneamente); veja na ajuda do Delphi o método TThread.Synchronize.


Paullsoftware
   - 20 mar 2006

certo, Massuda...
valeu pelos toques, agora acho que vai dar pra continuar o desenvolvimento do projeto! :wink: obrigado mais uma vez...
problema solucionado!


Paullsoftware
   - 21 mar 2006

Op´s surgiu outras dúvidas...

como desconectar ou enviar mensagem para todos os usuários conectados ao servidor???

não achei nos exemplos que olhei sobre o indy...


Massuda
   - 21 mar 2006

Um exemplo simples seria...#Código

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;
...note que entre o LockList e o UnlockList o servidor ficará bloqueado se alguém tentar conectar no servidor; isso acontece porque o servidor precisa incluir um no TIdPeerThread na lista Threads, mas esse código bloqueia a lista temporariamente; moral da estória: seja lá o que você for fazer com cada Peer, procure evitar executar cosias demoradas.


Paullsoftware
   - 21 mar 2006


Citação:
seja lá o que você for fazer com cada Peer, procure evitar executar cosias demoradas.
eu to pensando em algo como:
1 - Desconectar todos os Clientes;
2 - Desligar Todos os Clientes;
3 - Reiniciar Todos os Clientes;
4 - Liberar Todos os Clientes
algo desse tipo, tem problemas???


Massuda
   - 21 mar 2006

Aparentemente em todos os casos o cliente vai ter que desconectar do servidor. Pelo que entendi, não teria problemas, pois você vai apenas mandar um comando e acredito que não há necessidade de esperar o cliente executar o comando.


Paullsoftware
   - 21 mar 2006


Citação:
Aparentemente em todos os casos o cliente vai ter que desconectar do servidor. Pelo que entendi, não teria problemas, pois você vai apenas mandar um comando e acredito que não há necessidade de esperar o cliente executar o comando.
a ta, agora entendi, vc é que sempre que há o envio por parte de um deles client/servidor na sequencia eles ficam aguardando uma resposta do outro né isso?
eu imaginei isso também, por exemplo eu pensei em pedir dos clientes com o comando #HORA por exemplo, mais ai pensei: ele vai pedir a hora de todos e depois que o último receber o pedido é que ele vai processar a do primeiro, estou certo?


Massuda
   - 21 mar 2006

Talvez eu não tenha entendido, mas eu implementaria, por exemplo, o comando DESLIGAR assim....#Código

// código no servidor
var
List: TList;
Peer: TIdPeerThread;
...
List := IdTCPServer1.Threads.LockList;
try
for I := 0 to List.Count - 1 do begin
// List[I] é uma das threads do servidor
Peer := TIdPeerThread(List[I]);
Peer.Connection.WriteLn(´DESLIGAR´);
if Peer.Connection.ReadLn(10, 100{ms}) <> ´OK´ then begin
// loga/avisa que não respondeu
end;
end;
finally
IdTCPServer1.Threads.UnlockList;
end;

// código no cliente
...
Comando := IdTCPClient1.ReadLn;
if Comando = ´DESLIGAR´ then begin
IdTCPClient1.WriteLn(´OK´);
//prepara para desligar
end
...
...isso deve funcionar sem problemas no seu caso (lan house né?), onde o número de clientes ligados ao servidor é fixo.


Paullsoftware
   - 21 mar 2006

Massuda, eu crei uma procedure no servidor para enviar o comando par ao cliente assim:
#Código


procedure TfMain.SendAll(wTipo:String);
var
List : TList;
Peer : TIdPeerThread;
I : Integer;
begin
List := TCPServer.Threads.LockList;
try
for I := 0 to List.Count -1 do
begin
Peer := TIdPeerThread(List[i]);
if wTipo = UpperCase(´:1´) then
begin
Peer.Connection.WriteLn(´TELA´)
end
else
if wTipo = UpperCase(´:2´) then
begin
Peer.Connection.WriteLn(´STOP´)
end
else
if wTipo = UpperCase(´:3´) then
begin
Peer.Connection.WriteLn(´BLOCK´)
end
else
if wTipo = UpperCase(´:4´) then
begin
Peer.Connection.WriteLn(´LIBERA´)
end
else
if wTipo = UpperCase(´:5´) then
begin
Peer.Connection.WriteLn(´#REBOOT´)
end
else
if wTipo = UpperCase(´:6´) then
begin
Peer.Connection.WriteLn(´MSG´)
end
else
end;
finally
TCPServer.Threads.UnlockList;
end;
end;


e no client tenho uma Trhead assim:
procedure TReadingThread.Execute;
var
Command,cmd : String;
begin
With fMain do
begin
repeat
Command := UpperCase(FConn.ReadLn);
cmd := Command;
if Command = ´NET´ then
begin
FConn.WriteLn(IdTCPClient.Socket.LocalName+ ´ Desconectado do Servidor´);
lbStatus.Items.Insert(0,Command);
end;
if Command = ´BLOCK´ then
begin
FConn.WriteLn(IdTCPClient.Socket.LocalName+ ´ Bloqueado com sucesso!´);
lbStatus.Items.Insert(0,Command);
end;
if Command = ´#SHUTDOWN´ then
begin
FConn.WriteLn(IdTCPClient.Socket.LocalName+ ´ Desligado com sucesso!´);
lbStatus.Items.Insert(0,Command);
end;
if Command = ´LIBERA´ then
begin
FConn.WriteLn(IdTCPClient.Socket.LocalName+ ´ Liberado com sucesso!´);
lbStatus.Items.Insert(0,Command);
end;
if Command = ´REBOOT´ then
begin
FConn.WriteLn(IdTCPClient.Socket.LocalName+ ´ Reiniciado com sucesso!´);
lbStatus.Items.Insert(0,Command);
end;
if Command = ´TELA´ then
begin
FConn.WriteLn(´Tela copiado da Estação: ´ + IdTCPClient.Socket.LocalName);
lbStatus.Items.Insert(0,Command);
end;
if Command = ´STOP´ then
begin
FConn.WriteLn(IdTCPClient.Socket.LocalName+ ´ Tempo parado com sucesso!´);
lbStatus.Items.Insert(0,Command);
end;
cmd := UpperCase(Trim(Copy(cmd, 1, Pos(´:´, cmd)-1)));
if cmd = ´!´ then
begin
lbStatus.Items.Insert(0,´Liberado!´);
Button2.Enabled := True;
end
else
if cmd = ´?´ then
begin
lbStatus.Items.Insert(0,Command);
Button2.Enabled := False;
end;
until not IdTCPClient.Connected;
end;
end;
lembra? Ela ainda está incompleta, mais estou desenvolvendo primeiro o server, e fiz o código acima somente para testar, ainda não tá 100¬, mais acho que o caminho é por ai...
Eu tava olhando um dia desses o Projeto Lan-House, mais percebi que o pessoal abandonou ou estão se comunicando por outro lugar, pois, as mensagens que estão lá são muito antigas...


Massuda
   - 21 mar 2006


Citação:
...eu crei uma procedure no servidor para enviar o comando par ao cliente assim...mais acho que o caminho é por ai...
É isso mesmo.