plinho
asked on
Indy Client problem when receiving text
Hello,
I'm making a server and a client using idTCPServer and idTCPClient [indy9]. What I want is to make the client send text to the server, wich is kind of easy, and the server send text to the client, wich I can't figure where is my error...
Here is the code of my Client App:
unit TCPClientUnt;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection,
IdTCPClient, ExtCtrls;
type
TForm1 = class(TForm)
TCPClient: TIdTCPClient;
Edit3: TEdit;
Button2: TButton;
GroupBox1: TGroupBox;
Label3: TLabel;
Label4: TLabel;
Edit1: TEdit;
Edit2: TEdit;
Button1: TButton;
Memo1: TMemo;
Timer1: TTimer;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure TCPClientConnected(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure TCPClientDisconnected(Send er: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender : TObject);
begin
tcpclient.Host:=edit1.Text ;
tcpclient.Port:=strtoint(e dit2.text) ;
tcpclient.Connect(1000);
end;
procedure TForm1.Button2Click(Sender : TObject);
begin
with TCPClient do
begin
WriteLn(edit3.Text);
end;
end;
procedure TForm1.TCPClientConnected( Sender: TObject);
begin
timer1.enabled:=true;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
aText: string;
begin
with TCPClient do
begin
aText:=ReadLn('',10);
if (aText <> '') then
begin
Memo1.Lines.add('Received: ' + aText);
end;
end;
end;
procedure TForm1.TCPClientDisconnect ed(Sender: TObject);
begin
timer1.Enabled:=false;
end;
end.
When I put this timer, once the Client connects to the Server, it freezes.... What is wrong with my code?
I'm making a server and a client using idTCPServer and idTCPClient [indy9]. What I want is to make the client send text to the server, wich is kind of easy, and the server send text to the client, wich I can't figure where is my error...
Here is the code of my Client App:
unit TCPClientUnt;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection,
IdTCPClient, ExtCtrls;
type
TForm1 = class(TForm)
TCPClient: TIdTCPClient;
Edit3: TEdit;
Button2: TButton;
GroupBox1: TGroupBox;
Label3: TLabel;
Label4: TLabel;
Edit1: TEdit;
Edit2: TEdit;
Button1: TButton;
Memo1: TMemo;
Timer1: TTimer;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure TCPClientConnected(Sender:
procedure Timer1Timer(Sender: TObject);
procedure TCPClientDisconnected(Send
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender
begin
tcpclient.Host:=edit1.Text
tcpclient.Port:=strtoint(e
tcpclient.Connect(1000);
end;
procedure TForm1.Button2Click(Sender
begin
with TCPClient do
begin
WriteLn(edit3.Text);
end;
end;
procedure TForm1.TCPClientConnected(
begin
timer1.enabled:=true;
end;
procedure TForm1.Timer1Timer(Sender:
var
aText: string;
begin
with TCPClient do
begin
aText:=ReadLn('',10);
if (aText <> '') then
begin
Memo1.Lines.add('Received:
end;
end;
end;
procedure TForm1.TCPClientDisconnect
begin
timer1.Enabled:=false;
end;
end.
When I put this timer, once the Client connects to the Server, it freezes.... What is wrong with my code?
You could also stick the TCPClient inside a thread (with the above or similar code) and make a
.OnStringReceived() synchronized event
.OnStringReceived() synchronized event
ASKER
ok, I did that, the client is not freezing anymore, but when I try to send message to it I get an "I/O error 105" why that?
I suspect you are doing
WriteLn(s) or Readln instead of
TCPClient.WriteLn(s) or TCPClient.ReadLn
WriteLn(s) or Readln instead of
TCPClient.WriteLn(s) or TCPClient.ReadLn
ASKER
Well, I'm not at home, but the server code to send a string is something like this:
procedure TForm1.button1onclick(Asen der: TObject);
begin
with TCPServer do
WriteLn ( edit1.text );
end;
When i'm at home I'll post the code of the server and the client...
procedure TForm1.button1onclick(Asen
begin
with TCPServer do
WriteLn ( edit1.text );
end;
When i'm at home I'll post the code of the server and the client...
ASKER
Well I'm at home
here is the SERVER code:
unit TCPServerUnt;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPServer;
type
TForm1 = class(TForm)
TCPServer: TIdTCPServer;
Label1: TLabel;
Edit1: TEdit;
Memo1: TMemo;
Button1: TButton;
procedure TCPServerConnect(AThread: TIdPeerThread);
procedure TCPServerExecute(AThread: TIdPeerThread);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.TCPServerConnect(AT hread: TIdPeerThread);
begin
label1.Caption:= 'Connected';
Memo1.Lines.Add('Connected to ' + athread.Connection.Socket. Binding.IP );
end;
procedure TForm1.TCPServerExecute(AT hread: TIdPeerThread);
var
aText: string;
begin
aText:=athread.Connection. ReadLn('', 10);
if (aText <> '') then
begin
Memo1.Lines.Add(atext);
end;
end;
procedure TForm1.Button1Click(Sender : TObject);
begin
with TCPServer do
begin
Writeln(edit1.text);
end;
end;
end.
and here the CLIENT code:
unit TCPClientUnt;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection,
IdTCPClient, ExtCtrls, IDException;
type
TForm1 = class(TForm)
TCPClient: TIdTCPClient;
Edit3: TEdit;
Button2: TButton;
GroupBox1: TGroupBox;
Label3: TLabel;
Label4: TLabel;
Edit1: TEdit;
Edit2: TEdit;
Button1: TButton;
Memo1: TMemo;
Timer1: TTimer;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure TCPClientConnected(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure TCPClientDisconnected(Send er: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender : TObject);
begin
tcpclient.Host:=edit1.Text ;
tcpclient.Port:=strtoint(e dit2.text) ;
tcpclient.Connect(1000);
end;
procedure TForm1.Button2Click(Sender : TObject);
begin
with TCPClient do
begin
WriteLn(edit3.Text);
end;
end;
procedure TForm1.TCPClientConnected( Sender: TObject);
begin
timer1.enabled:=true;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
aText: string;
begin
aText:='';
timer1.Enabled:=false;
try
TCPClient.ReadTimeout:=10;
try
aText:=TCPClient.ReadLn;
if (aText <> '') then
begin
Memo1.Lines.add('Received: ' + aText);
end;
except
on EIdReadTimeout do //nothing
end;
finally
timer1.enabled:=true;
TCPClient.ReadTimeout:=0;
end;
end;
procedure TForm1.TCPClientDisconnect ed(Sender: TObject);
begin
timer1.Enabled:=false;
end;
end.
What should I do?
here is the SERVER code:
unit TCPServerUnt;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPServer;
type
TForm1 = class(TForm)
TCPServer: TIdTCPServer;
Label1: TLabel;
Edit1: TEdit;
Memo1: TMemo;
Button1: TButton;
procedure TCPServerConnect(AThread: TIdPeerThread);
procedure TCPServerExecute(AThread: TIdPeerThread);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.TCPServerConnect(AT
begin
label1.Caption:= 'Connected';
Memo1.Lines.Add('Connected
end;
procedure TForm1.TCPServerExecute(AT
var
aText: string;
begin
aText:=athread.Connection.
if (aText <> '') then
begin
Memo1.Lines.Add(atext);
end;
end;
procedure TForm1.Button1Click(Sender
begin
with TCPServer do
begin
Writeln(edit1.text);
end;
end;
end.
and here the CLIENT code:
unit TCPClientUnt;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection,
IdTCPClient, ExtCtrls, IDException;
type
TForm1 = class(TForm)
TCPClient: TIdTCPClient;
Edit3: TEdit;
Button2: TButton;
GroupBox1: TGroupBox;
Label3: TLabel;
Label4: TLabel;
Edit1: TEdit;
Edit2: TEdit;
Button1: TButton;
Memo1: TMemo;
Timer1: TTimer;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure TCPClientConnected(Sender:
procedure Timer1Timer(Sender: TObject);
procedure TCPClientDisconnected(Send
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender
begin
tcpclient.Host:=edit1.Text
tcpclient.Port:=strtoint(e
tcpclient.Connect(1000);
end;
procedure TForm1.Button2Click(Sender
begin
with TCPClient do
begin
WriteLn(edit3.Text);
end;
end;
procedure TForm1.TCPClientConnected(
begin
timer1.enabled:=true;
end;
procedure TForm1.Timer1Timer(Sender:
var
aText: string;
begin
aText:='';
timer1.Enabled:=false;
try
TCPClient.ReadTimeout:=10;
try
aText:=TCPClient.ReadLn;
if (aText <> '') then
begin
Memo1.Lines.add('Received:
end;
except
on EIdReadTimeout do //nothing
end;
finally
timer1.enabled:=true;
TCPClient.ReadTimeout:=0;
end;
end;
procedure TForm1.TCPClientDisconnect
begin
timer1.Enabled:=false;
end;
end.
What should I do?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks TheRealLoki!! And could you answer a last question??
When I close the server without closing the connection the client gets A LOT of "Connection closed gracefully.". That's because of the timer isn't it? What can i do to prevent this?
When I close the server without closing the connection the client gets A LOT of "Connection closed gracefully.". That's because of the timer isn't it? What can i do to prevent this?
put a check in teh OnTimer event for the exception, and close your connection. Then only have the timer "rearm" if the connection is alive
eg.
procedure TForm1.Timer1Timer(Sender: TObject);
var
aText: string;
begin
aText := '';
timer1.enabled := false;
try
TCPClient.ReadTimeout := 10;
try
aText:=TCPClient.ReadLn;
if (aText <> '') then
begin
Memo1.Lines.add('Received: ' + aText);
end;
except
on EIDReadTimeout do ; //ignore timeouts
on e: exception do
begin
timer1.enabled := false;
TCPClient.Disconnect;
// raise; <-- raise if you want to show the user, or do memo1.lines.add(e.message) ; to log etc...
end
end;
finally
TCPClient.ReadTimeout := 0; // reset to normal
if TCPClient.Connected then
timer1.enabled := true; // only rearm if connected
end;
end;
eg.
procedure TForm1.Timer1Timer(Sender:
var
aText: string;
begin
aText := '';
timer1.enabled := false;
try
TCPClient.ReadTimeout := 10;
try
aText:=TCPClient.ReadLn;
if (aText <> '') then
begin
Memo1.Lines.add('Received:
end;
except
on EIDReadTimeout do ; //ignore timeouts
on e: exception do
begin
timer1.enabled := false;
TCPClient.Disconnect;
// raise; <-- raise if you want to show the user, or do memo1.lines.add(e.message)
end
end;
finally
TCPClient.ReadTimeout := 0; // reset to normal
if TCPClient.Connected then
timer1.enabled := true; // only rearm if connected
end;
end;
ASKER
thanks =)
aText:=ReadLn('',10);
line
Indy will wait at this point until the server sends a sting back
Just get your server to reply and you'll be away again
I am guessing you were trying to have it check for a string, waiting 10 ms and then carry on.
You can do the same thing by the folowing
uses IDException;
...
procedure TForm1.Timer1Timer(Sender:
var
aText: string;
begin
aText := '';
timer1.enabled := false;
try
TCPClient.ReadTimeout := 10;
try
aText:=TCPClient.ReadLn;
if (aText <> '') then
begin
Memo1.Lines.add('Received:
end;
except
on EIDReadTimeout do ; //ignore timeouts
end;
finally
timer1.enabled := true;
TCPClient.ReadTimeout := 0; // reset to normal
end;
end;
If this is the approach you are after, and you wish for a "non-blocking" implementation, I'd recommend ICS instead