Solved

Indy Client problem when receiving text

Posted on 2006-11-06
10
938 Views
Last Modified: 2008-01-09
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(Sender: 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(edit2.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.TCPClientDisconnected(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?
0
Comment
Question by:plinho
  • 5
  • 5
10 Comments
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 17885926
it is freezing because of the
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: 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
    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
0
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 17885942
You could also stick the TCPClient inside a thread (with the above or similar code) and make a
.OnStringReceived() synchronized event
0
 

Author Comment

by:plinho
ID: 17893958
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?
0
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 17901950
I suspect you are doing
WriteLn(s) or Readln instead of
TCPClient.WriteLn(s) or TCPClient.ReadLn
0
 

Author Comment

by:plinho
ID: 17905398
Well, I'm not at home, but the server code to send a string is something like this:

procedure TForm1.button1onclick(Asender: 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...
0
Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

 

Author Comment

by:plinho
ID: 17907906
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(AThread: TIdPeerThread);
begin
label1.Caption:= 'Connected';
Memo1.Lines.Add('Connected to ' + athread.Connection.Socket.Binding.IP);
end;

procedure TForm1.TCPServerExecute(AThread: 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(Sender: 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(edit2.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.TCPClientDisconnected(Sender: TObject);
begin
timer1.Enabled:=false;
end;

end.


What should I do?
0
 
LVL 17

Accepted Solution

by:
TheRealLoki earned 125 total points
ID: 17908080
The server code for sending is incomplete
you need to tell the server "which" client to send to , or to all...

  with TCPServer do
    begin
    Writeln(edit1.text);
    end;
The  above will not work - there is no TCPServer.WriteLn
You should change it to :-

    with TCPServer.Threads.LockList do // Loop through all the connections
    try
        for i := 0 to Count - 1 do
        begin
              TIdPeerThread(Items[i]).Connection.Writeln(edit1.text); // write to each connection
        end;
     finally
        TCPServer.Threads.UnLockList;
     end;
0
 

Author Comment

by:plinho
ID: 17908956
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?
0
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 17910035
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;
0
 

Author Comment

by:plinho
ID: 17910609
thanks =)
0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now