 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Ian Groves Guest
|
Posted: Tue Aug 15, 2006 5:40 pm Post subject: idTCPClient & idTCPServer |
|
|
Indy 10.0.0.52 - D7
I am trying to make a simple app where a client (idtcpclient) connects to a
server (idtcpserver) and exchanges info, my problem is stores connection
specific info for example...
This is my simple protocol at the moment....
procedure TMainForm.IdTCPServer1Execute(AContext: TIdContext);
var
Param: Integer;
Data: string;
aUserName, aPassword: string; <<<<<<<<<<<<<<<<<THIS IS MY PROBLEM AT THE
MOMENT
begin
Data := AContext.Connection.Socket.ReadLn;
Param := StrToInt(Copy(Data, 1, 2));
Delete(Data, 1, 2);
case Param of
10: Log('Client is version: ' + Data);
11: begin
aUsername := Data;
Log('Client Username is: ' + aUsername);
end;
12: begin
aPassword := Data;
Log('Client Password is: ' + aPassword);
end;
99: Log(aUsername + ' - Client sends message: ' + Data);
end;
end;
When 2 clients connect i cant determine which one I am dealing with as
aUsername and aPassword are clearerd each time some data is sent, I presume
i need to attach this info to AContext somehow, but how do I do this.
Thanks in advance.
Ian Groves |
|
| Back to top |
|
 |
Martin James Guest
|
Posted: Tue Aug 15, 2006 6:06 pm Post subject: Re: idTCPClient & idTCPServer |
|
|
| Quote: |
When 2 clients connect i cant determine which one I am dealing with as
aUsername and aPassword are clearerd each time some data is sent, I presume
i need to attach this info to AContext somehow,
|
Exactly.
but how do I do this.
These 'socket context' thingies can usually be descended from to give
extra fields or contain an auxiliary 'data' pointer or object reference
that can contain a record/object that holds connection-specific data.
It is common to create such an object upon initial connection.
Rgds,
Martin |
|
| Back to top |
|
 |
Ian Groves Guest
|
Posted: Tue Aug 15, 2006 6:20 pm Post subject: Re: idTCPClient & idTCPServer |
|
|
Could you point me in the direction of a simple example.
Many Thanks
"Martin James" <nospam (AT) dial (DOT) pipex.com> wrote in message
news:44e1c6b8$1 (AT) newsgroups (DOT) borland.com...
| Quote: |
When 2 clients connect i cant determine which one I am dealing with as
aUsername and aPassword are clearerd each time some data is sent, I
presume i need to attach this info to AContext somehow,
Exactly.
but how do I do this.
These 'socket context' thingies can usually be descended from to give
extra fields or contain an auxiliary 'data' pointer or object reference
that can contain a record/object that holds connection-specific data. It
is common to create such an object upon initial connection.
Rgds,
Martin |
|
|
| Back to top |
|
 |
Martin James Guest
|
Posted: Tue Aug 15, 2006 7:19 pm Post subject: Re: idTCPClient & idTCPServer |
|
|
Ian Groves wrote:
| Quote: | Could you point me in the direction of a simple example.
Many Thanks
|
Well, I do not have Indy 10 loaded at the moment but, looking at
idContext.pas and idtask.pas, it seems like you could use either method:
TidContext has:
TIdContext = class;
TIdContextClass = class of TIdContext;
This strongly suggests that the server has a 'contextClass' class
property that can be loaded with the class of a TidContext descendant.
This would allow the server to create your custom TidContext class,
(with its added 'password' and 'username' fields'), whenever it needed
to, eg. upon client connect. I'm guessing that this is the 'proper' way
to meet your requirements, though Remy Lebeau is the real expert. You
will probably have to typecast the passed TidContext to your descendant
class in the OnExecute.
Failing that, TidContext is descended from TidTask which has:
FData: TObject;
...
property Data: TObject read FData write FData;
This 'data' could be anything you want, eg simply:
TconnectionData=class(TObject)
password:string;
userName:string;
end;
In the OnConnect handler, you could create one of these and store it in
the 'data' field. You could then typecast 'TidContext.data' back to
'TconnectionData'in OnExecute. Note that Indy has, or had, a habit of
auto-freeing the 'data' object upon disconnect, (assuming it is
assigned). This can be looked upon as useful or an OO design error <g>.
I do not know whether this behaviour has been continued into Indy
10. If not, you will have to free your 'data' object upon disconnection
to prevent leaks.
Rgds,
Martin |
|
| Back to top |
|
 |
Ian Groves Guest
|
Posted: Tue Aug 15, 2006 7:29 pm Post subject: Re: idTCPClient & idTCPServer |
|
|
Thanks very much
"Martin James" <nospam (AT) dial (DOT) pipex.com> wrote in message
news:44e1d7c9 (AT) newsgroups (DOT) borland.com...
| Quote: | Ian Groves wrote:
Could you point me in the direction of a simple example.
Many Thanks
Well, I do not have Indy 10 loaded at the moment but, looking at
idContext.pas and idtask.pas, it seems like you could use either method:
TidContext has:
TIdContext = class;
TIdContextClass = class of TIdContext;
This strongly suggests that the server has a 'contextClass' class property
that can be loaded with the class of a TidContext descendant. This would
allow the server to create your custom TidContext class, (with its added
'password' and 'username' fields'), whenever it needed to, eg. upon client
connect. I'm guessing that this is the 'proper' way to meet your
requirements, though Remy Lebeau is the real expert. You will probably
have to typecast the passed TidContext to your descendant class in the
OnExecute.
Failing that, TidContext is descended from TidTask which has:
FData: TObject;
..
property Data: TObject read FData write FData;
This 'data' could be anything you want, eg simply:
TconnectionData=class(TObject)
password:string;
userName:string;
end;
In the OnConnect handler, you could create one of these and store it in
the 'data' field. You could then typecast 'TidContext.data' back to
'TconnectionData'in OnExecute. Note that Indy has, or had, a habit of
auto-freeing the 'data' object upon disconnect, (assuming it is assigned).
This can be looked upon as useful or an OO design error <g>. I do not know
whether this behaviour has been continued into Indy 10. If not, you will
have to free your 'data' object upon disconnection to prevent leaks.
Rgds,
Martin
|
|
|
| Back to top |
|
 |
Remy Lebeau (TeamB) Guest
|
Posted: Wed Aug 16, 2006 1:44 am Post subject: Re: idTCPClient & idTCPServer |
|
|
"Ian Groves" <ian (AT) REMOVE_THIS_BITigroves (DOT) f9.co.uk> wrote in message
news:44e1c0d5 (AT) newsgroups (DOT) borland.com...
That is an old version. You should consider upgrading to the 101.5
snapshot.
| Quote: | When 2 clients connect i cant determine which one I am dealing with
|
That is what the TIdContext parameter is for.
| Quote: | as aUsername and aPassword are clearerd each time some data is sent
|
As they should be, since they are local variables to the event handler and
will go out of scope when the handler exits. You have to store your values
outside of the event handler in order to persist them.
| Quote: | I presume i need to attach this info to AContext somehow
|
That is one way to do it.
| Quote: | but how do I do this.
|
TIdContext has a Data property that you can use. Create a new class that
holds your per-connection information, and then instantiate that class in
the server's OnConnect event and free it in the OnDisconnect event, ie:
type
TMyData = class
public
UserName: String;
Password: String;
end;
procedure TMainForm.IdTCPServer1Connect(AContext: TIdContext);
begin
AContext.Data := TMyData.Create;
end;
procedure TMainForm.IdTCPServer1Disconnect(AContext: TIdContext);
begin
AContext.Data.Free;
AContext.Data := nil; // <-- important
end;
procedure TMainForm.IdTCPServer1Execute(AContext: TIdContext);
var
Param: Integer;
Data: string;
begin
Data := AContext.Connection.IOHandler.ReadLn;
Param := StrToInt(Copy(Data, 1, 2));
Delete(Data, 1, 2);
case Param of
10: Log('Client is version: ' + Data);
11:
begin
TMyData(AContext.Data).Username := Data;
Log('Client Username is: ' + Data);
end;
12:
begin
TMyData(AContext.Data).Password := Data;
Log('Client Password is: ' + Data);
end;
99: Log(TMyData(AContext.Data).Username + ' - Client sends
message: ' + Data);
end;
end;
Alternatively, you can derive a new class from TIdContext, and then assign
it to the server's ContextClass before activating the server, ie:
type
TMyContext = class(TIdContext)
public
UserName: String;
Password: String;
end;
constructor TMainForm.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
IdTCPServer1.ContextClass := TMyContext;
//...
end;
procedure TMainForm.IdTCPServer1Execute(AContext: TIdContext);
var
Param: Integer;
Data: string;
begin
Data := AContext.Connection.IOHandler.ReadLn;
Param := StrToInt(Copy(Data, 1, 2));
Delete(Data, 1, 2);
case Param of
10: Log('Client is version: ' + Data);
11:
begin
TMyContext(AContext).Username := Data;
Log('Client Username is: ' + Data);
end;
12:
begin
TMyContext(AContext).Password := Data;
Log('Client Password is: ' + Data);
end;
99: Log(TMyContext(AContext).Username + ' - Client sends
message: ' + Data);
end;
end;
Gambit |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|