Board index » delphi » Indy Tcpserver

Indy Tcpserver


2004-10-04 02:02:54 AM
delphi83
Why won't this code echo back anything? I am testing it with Telnet but
cannot get it to talk back to my telnet client. I do not get anything in
the memo when I type in the client either.
Matt
procedure TMainForm.IdTCPServer1Execute(AThread: TIdPeerThread);
var
sCommand: string;
Stage: Integer;
begin
Stage := 1;
while Athread.Connection.Connected do begin
with Athread.Connection do try
sCommand := ReadLn;
Memo.Lines.Add(sCommand);
Inc(Stage);
WriteLn(IntToStr(Stage));
WriteLn(sCommand);
except
Beep;
end;
end;
end;
 
 

Re:Indy Tcpserver

"Matthew H" <XXXX@XXXXX.COM>writes
Quote
Why won't this code echo back anything? I am testing it with Telnet but
cannot get it to talk back to my telnet client. I do not get anything in
the memo when I type in the client either.
Does the client connect up?
Does the execution reach the ReadLn?
Does the ReadLn ever return?
If the ReadLn does not return, do the terminator/s sent by the client match
those expected by ReadLn?
If 'Memo' is a VCL Tmemo component, you should not access it directly from
non-main threads.
Rgds,
Martin
 

Re:Indy Tcpserver

Quote
>Why won't this code echo back anything? I am testing it with Telnet but
>cannot get it to talk back to my telnet client. I do not get anything
in
>the memo when I type in the client either.

Does the client connect up?
Yes.
Quote
Does the execution reach the ReadLn?
Yes.
Quote
Does the ReadLn ever return?
No.
Quote
If the ReadLn does not return, do the terminator/s sent by the client
match
those expected by ReadLn?
I suspected that too but tried both:
sCommand := ReadLn(#13); and sCommand := ReadLn(#10);
And neither worked. I am using Putty.exe as telnet client.
Quote
If 'Memo' is a VCL Tmemo component, you should not access it directly from
non-main threads.
I am sure your right but it was thrown in as a simple diagnostic to figure
out what was going on here.
Matthew
Quote
Rgds,
Martin


 

Re:Indy Tcpserver

Quote

sCommand := ReadLn(#13); and sCommand := ReadLn(#10);

And neither worked. I am using Putty.exe as telnet client.
I opened a new project & plonked a TidTCPServer onto the form, setting the
binding to 0.0.0.0:23. I set the server active in the formCreate event &
copied/pasted the following into the onExecute event:
procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var
sCommand: string;
Stage: Integer;
begin
Stage := 1;
while Athread.Connection.Connected do begin
with Athread.Connection do try
sCommand := ReadLn;
Inc(Stage);
WriteLn(IntToStr(Stage));
WriteLn(sCommand);
except
Beep;
end;
end;
end;
I put breakpoints on the ReadLn and WriteLn & ran the project.
Telnetting to 'localhost' with M$ 'telnet.exe' caused the first breakpoint
to fire. Pressed F9, ReadLn blocks. Entered some gunge at the telnet app &
pressed 'enter' - the second breakpoint fired.
Seems to work OK with Indy 9.0.14.
Rgds,
Martin
 

Re:Indy Tcpserver

I got it to go. CommandHandlersEnabled was set to true. Changed it to
false and started to work. I never set it to true and do not know why it
would be enabled by default. Weird.
Thanks.
Matthew
Quote
I opened a new project & plonked a TidTCPServer onto the form, setting the
binding to 0.0.0.0:23. I set the server active in the formCreate event &
copied/pasted the following into the onExecute event:


procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var
sCommand: string;
Stage: Integer;
begin
Stage := 1;
while Athread.Connection.Connected do begin
with Athread.Connection do try
sCommand := ReadLn;
Inc(Stage);
WriteLn(IntToStr(Stage));
WriteLn(sCommand);
except
Beep;
end;
end;
end;

I put breakpoints on the ReadLn and WriteLn & ran the project.

Telnetting to 'localhost' with M$ 'telnet.exe' caused the first breakpoint
to fire. Pressed F9, ReadLn blocks. Entered some gunge at the telnet app
&
pressed 'enter' - the second breakpoint fired.

Seems to work OK with Indy 9.0.14.

Rgds,
Martin
 

Re:Indy Tcpserver

"Matthew H" <XXXX@XXXXX.COM>writes
Quote
I got it to go. CommandHandlersEnabled was set to true.
Changed it to false and started to work. I never set it to
true and do not know why it would be enabled by default.
The CommandHandlersEnabled property is supposed to be True by default, it is
hard-coded for that. However, there has to be actual entries in the
CommandHandlers collection before they can actually be used. If
CommandHandlersEnabled is True and there is at least 1 entry in the
collection, the the OnExecute event is ignored completely and never
triggered.
Gambit
 

Re:Indy Tcpserver

"Matthew H" <XXXX@XXXXX.COM>writes
Quote
Why won't this code echo back anything?
There are several mistakes with your code.
Quote
while Athread.Connection.Connected do begin
Get rid of that altogether. You should NOT be looping like that at all.
The OnExecute event is already looped by TIdTCPServer automatically, and in
fact performing that kind of loop manually interfers with TIdTCPServer's
internal connection management.
Quote
Memo.Lines.Add(sCommand);
The OnExecute event is multi-threaded. That line of code is NOT
thread-safe. You are probably deadlocking your code, that would explain the
lack of echoing. If you need to display the input commands, then you MUST
use the thread's Synchronize() method in order to access the Memo in a
thread-safe manner. Look at the TIdSync class to help you with that.
Use this code instead:
type
MemoSync = class(TIdSync)
private
FMemo: TMemo;
FStr: String;
protected
procedure DoSynchronize; override;
public
constructor Create(AThread: TIdThread; AMemo: TMemo; AStr:
String);
class procedure Add(AThread: TIdThread; AMemo: TMemo; AStr:
String);
end;
constructor MemoSync.Create(AThread: TIdThread; AMemo: TMemo; AStr:
String);
begin
inherited Create(AThread);
FMemo := AMemo;
FStr := AStr;
end;
procedure MemoSync.DoSynchronize;
begin
FMemo.Lines.Add(FStr);
end;
class procedure MemoSync.Add(AThread: TIdThread; AMemo: TMemo; AStr:
String);
begin
with MemoSync.Create(AThread, AMemo, AStr) do
try
Synchronize;
finally
Free;
end;
end;
procedure TMainForm.IdTCPServer1Connect(AThread: TIdPeerThread);
begin
AThread.Data := TObject(1);
end;
procedure TMainForm.IdTCPServer1Execute(AThread: TIdPeerThread);
var
sCommand: string;
Stage: Integer;
begin
Stage := Integer(AThread.Data);
with AThread.Connection do try
sCommand := ReadLn;
MemoSync.Add(AThread, Memo1, sCommand);
WriteLn(IntToStr(Stage));
WriteLn(sCommand);
AThread.Data := TObject(Stage+1);
end;
end;
Gambit
 

Re:Indy Tcpserver

Quote
>while Athread.Connection.Connected do begin

Get rid of that altogether. You should NOT be looping like that at all.
The OnExecute event is already looped by TIdTCPServer automatically, and
in
fact performing that kind of loop manually interfers with TIdTCPServer's
internal connection management.
Will the variables be lost everytime it loops though?
Quote
>Memo.Lines.Add(sCommand);

The OnExecute event is multi-threaded. That line of code is NOT
thread-safe. You are probably deadlocking your code, that would explain
the
lack of echoing. If you need to display the input commands, then you MUST
use the thread's Synchronize() method in order to access the Memo in a
thread-safe manner. Look at the TIdSync class to help you with that.
I know that. I just threw that in there to trouble shoot this.
Quote
Use this code instead:
I will do that. Thanks.
Matthew
Quote
type
MemoSync = class(TIdSync)
private
FMemo: TMemo;
FStr: String;
protected
procedure DoSynchronize; override;
public
constructor Create(AThread: TIdThread; AMemo: TMemo; AStr:
String);
class procedure Add(AThread: TIdThread; AMemo: TMemo; AStr:
String);
end;

constructor MemoSync.Create(AThread: TIdThread; AMemo: TMemo; AStr:
String);
begin
inherited Create(AThread);
FMemo := AMemo;
FStr := AStr;
end;

procedure MemoSync.DoSynchronize;
begin
FMemo.Lines.Add(FStr);
end;

class procedure MemoSync.Add(AThread: TIdThread; AMemo: TMemo; AStr:
String);
begin
with MemoSync.Create(AThread, AMemo, AStr) do
try
Synchronize;
finally
Free;
end;
end;

procedure TMainForm.IdTCPServer1Connect(AThread: TIdPeerThread);
begin
AThread.Data := TObject(1);
end;

procedure TMainForm.IdTCPServer1Execute(AThread: TIdPeerThread);
var
sCommand: string;
Stage: Integer;
begin
Stage := Integer(AThread.Data);
with AThread.Connection do try
sCommand := ReadLn;
MemoSync.Add(AThread, Memo1, sCommand);
WriteLn(IntToStr(Stage));
WriteLn(sCommand);
AThread.Data := TObject(Stage+1);
end;
end;


Gambit


 

Re:Indy Tcpserver

"Matthew H" <XXXX@XXXXX.COM>writes
Quote
Will the variables be lost everytime it loops though?
The local variables, yes. Which is why I was storing the Stage value into
the thread's Data property, so that it could be preserved from one loop
iteration to the next.
Quote
I know that. I just threw that in there to trouble shoot this.
Well, it is not going to help you much if your troubleshooting code is in
its own trouble.
Gambit