Board index » delphi » Sending an unsolicited message from Indy server

Sending an unsolicited message from Indy server


2008-07-17 01:12:11 PM
delphi15
I have an Indy client application and an indy server application. there
are occasions that I want to send an unsolicited message from the server
to the client. This is done so that the client isn't constantly polling
the server to check the value of a flag. I want to send the client an
indicator that it can check for to see of the server has some data for
it. If the client finds that the flag is set then it will query the
server for the messages. My question is do I need to use a tcpclient
component on the server to do this unsolicited communication? It
doens't seem feasible to use the existing tcpserver component to send an
unsolicited message to the client PC.
 
 

Re:Sending an unsolicited message from Indy server

I have an Indy client application and an indy server application. There
are occasions that I want to send an unsolicited message from the server
to the client. This is done so that the client isn't constantly polling
the server to check the value of a flag. I want to send the client an
indicator that it can check for to see if the server has some data for
it. If the client finds that the flag is set then it will query the
server for the messages. My question is do I need to use a tcpclient
component on the server to do this unsolicited communication? It seems
like each client needs to have a tcpserver to receive this communication
since this message can be sent at any time. It doesn't seem feasible to
use the existing (primary) tcpserver component to send an unsolicited
message to the client PC.
 

Re:Sending an unsolicited message from Indy server

Jamie Dale writes:
Quote
D-Fan,

Just setup a reading thread for your TCPClient.

Have it loop frequently to ReadLn() and see if there are any new messages
sent. If so, process them..

At the server end you just need to send the message to the correct AThread
or Context as and when you need to. The client will be looping through its
reading thread and will automatically read it when the message is sent to
it.

No need for a server at the client end ;)

Hope that helps


"D-Fan" <XXXX@XXXXX.COM>writes
news:487ed92c$XXXX@XXXXX.COM...
>I have an Indy client application and an indy server application. There
>are occasions that I want to send an unsolicited message from the server to
>the client. This is done so that the client isn't constantly polling the
>server to check the value of a flag. I want to send the client an
>indicator that it can check for to see if the server has some data for it.
>If the client finds that the flag is set then it will query the server for
>the messages. My question is do I need to use a tcpclient component on the
>server to do this unsolicited communication? It seems like each client
>needs to have a tcpserver to receive this communication since this message
>can be sent at any time. It doesn't seem feasible to use the existing
>(primary) tcpserver component to send an unsolicited message to the client
>PC.


I can not seem to write to a client from a server unless I am in the
execute event of a server. This gives me exposure to the
Acontext.iohandler where I can converse with the client. This means
that the client has to initiate the request. In order to reduce the
traffix across the network I want the server to initiate the request by
sending a certain flag (value) to the client.
 

Re:Sending an unsolicited message from Indy server

"D-Fan" <XXXX@XXXXX.COM>writes
Quote
I can not seem to write to a client from a server unless I am in the execute
event of a server.
Thats because you haven't looped through your list of clients/contexts which
IdTCPServer holds.
In Indy 9 you can use something like this:
var
List: TList;
I: Integer;
begin
List := IdTCPServer1.Contexts.LockList;
For I := 0 to List.Count -1 do
begin
If TIdContext(List.Items[I]).Binding.PeerIP = {IP of client or other
criteria to match} then
begin
TIdContext(List.Items[I]).Connection.IOHandler.WriteLn('Command
here');
end;
end;
That will make the server write to the selected connection - Which will be
read at the other end by the Reading thread which is looping (on a timeout
to prevent errors when destroying the thread). Timeout can be used like
this:
IdTCPClient1.IOHandler.ReadLn('', 500);
500 is the milliseconds to wait - 1000 is 1 second.
I recommend always using a timeout - especially while in a thread as it can
cause problems if you want to update thread properties or destroy it etc. If
you want infinate time out just use ReadLn; - EG No () or parameters.
If you want to use a Timeout but don't want to execute code for nothing
then:
//Read: String;
Read := IdTCPClient1.IOHandler.ReadLn('', 500);
If Read <>'' then
begin
//Do stuff here...
end;
Quote
This gives me exposure to the Acontext.iohandler where I can converse
with the client. This means that the client has to initiate the request.
It only looks like that because not much is mentioned in the Indy docs on
how to initiate communication from the server to the client. If you follow
the example above you will see you can access any AContext outside of the
execute handler.
Quote
In order to reduce the traffix across the network I want the server to
initiate the request by sending a certain flag (value) to the client.
Thats one way of doing it and it is certainly simpler but should you ever
develop your own protocol to which other developers have access then you are
relying on them to poll your server and stick to your protocol standards. If
you send commands directly from your server then they are forced to read all
comms and react accordingly.
You can also keep your own list of clients when a new client connects -
Thats a thought for the future...
Hope that helps!
 

Re:Sending an unsolicited message from Indy server

"Jamie Dale" <XXXX@XXXXX.COM>writes
Quote
In Indy 9 you can use something like this:
My bad, that should be 'Indy 10'
Soz..
 

Re:Sending an unsolicited message from Indy server

Jamie Dale writes:
Quote
"Jamie Dale" <XXXX@XXXXX.COM>writes
news:XXXX@XXXXX.COM...

>In Indy 9 you can use something like this:

My bad, that should be 'Indy 10'

Soz..


This will probably solve my problem and allow me to stick to the single
server component that I initially wanted. Thanks for your help.
 

Re:Sending an unsolicited message from Indy server

"D-Fan" <XXXX@XXXXX.COM>writes
Quote
Jamie Dale writes:
>"Jamie Dale" <XXXX@XXXXX.COM>writes
>news:XXXX@XXXXX.COM...
>
>>In Indy 9 you can use something like this:
>
>My bad, that should be 'Indy 10'
>
>Soz..
This will probably solve my problem and allow me to stick to the single
server component that I initially wanted. Thanks for your help.
No problem!
Forgot to add this line of code though - You should always unlock() the
servers context list once you're done with it and also free the List:
IdTCPServer1.Contexts.UnLockList;
List.Free;
Sorry I fogot!
 

Re:Sending an unsolicited message from Indy server

"Jamie Dale" <XXXX@XXXXX.COM>writes
Quote
Just setup a reading thread for your TCPClient.
It is more complicated than just that.
Gambit
 

Re:Sending an unsolicited message from Indy server

"D-Fan" <XXXX@XXXXX.COM>writes
Quote
I can not seem to write to a client from a server unless
I am in the execute event of a server.
Yes, you can. Simply lock the server's Contexts list, find the desired
connection in it, and write your data to it. You just have to make sure you
do the writing in a thread-safe manner so as not to overlap with any data
the OnExecute handler tries to write at the same time.
Quote
This gives me exposure to the Acontext.iohandler where I can
converse with the client. This means that the client has to initiate
the request.
No, it does not.
Gambit
 

Re:Sending an unsolicited message from Indy server

"Jamie Dale" <XXXX@XXXXX.COM>writes
Quote
TIdContext(List.Items[I]).Connection.IOHandler.WriteLn('Command
here');
You need to implement a separate lock for the connection so the OnExecute
handler can not write its own data at the same time. Otherwise, the data from
the two threads (the one firing OnExecute, and the one looping through the
Contexts list) can overlap, corrupting the communication.
Gambit
 

Re:Sending an unsolicited message from Indy server

"Remy Lebeau (TeamB)" <XXXX@XXXXX.COM>writes
Quote

"Jamie Dale" <XXXX@XXXXX.COM>writes
news:XXXX@XXXXX.COM...

>You should always unlock() the servers context list once
>you're done with it and also free the List:
>
>IdTCPServer1.Contexts.UnLockList;
>
>List.Free;

DO NOT FREE THE LIST!!!! It is owned by the TThreadList for the Contexts
property, which in turn is owned by the TIdTCPServer.
Heh, learn something new every day...
I had wondered about this in the past but found example code somewhere that
did free it so stuck with it. Strangely it always seems to work too!
I'd better go and edit that line out of my code....
cheers remy
 

Re:Sending an unsolicited message from Indy server

"Remy Lebeau (TeamB)" <XXXX@XXXXX.COM>writes
Quote

Not any of the code I have every posted. Such code would sure cause random
AVs after the first unsolicted message is sent.
I never said that! Remy we all know you're a better coder than that!
Its sample source I remember seeing on the web once ages ago.
 

Re:Sending an unsolicited message from Indy server

When I finish my coding can I get you to review it for a fee?
Remy Lebeau (TeamB) writes:
Quote
"D-Fan" <XXXX@XXXXX.COM>writes
news:487ed92c$XXXX@XXXXX.COM...

>I have an Indy client application and an indy server application. There
>are occasions that I want to send an unsolicited message
>from the server to the client.

Please go to www.deja.com and search the newsgroup archives. This
has been discussed many times before.

>do I need to use a tcpclient component on the server to do
>this unsolicited communication?

No. You can send the message using the existing connection. But you have
to redesign your protocol at the data level to be asynchronous in order to
support such messages, and you have to use outbound queues on the server
side so unsolicated messages do not overlap replies to client commands, and
you can not use SendCmd() on the client side anymore since it may receive an
unsolicated message instead of a command reply.

>It seems like each client needs to have a tcpserver to receive
>this communication since this message can be sent at any time.

No, it does not. That would just lead to problems with firewalls and
routers anyway.

>It doesn't seem feasible to use the existing (primary) tcpserver component
>to send an unsolicited message to the client PC.

It is feasible, if implemented properly.


Gambit


 

Re:Sending an unsolicited message from Indy server

"D-Fan" <XXXX@XXXXX.COM>writes
Quote
When I finish my coding can I get you to review it for a fee?
Remy does offer consulting - Check out his site:
www.lebeausoftware.org/consulting.aspx
@Remy... That right click message is a pain. You have no idea the lengths I
went to so I could copy and paste that URL to get you some possible
business...
 

Re:Sending an unsolicited message from Indy server

"Jamie Dale" <XXXX@XXXXX.COM>writes
Quote
@Remy... That right click message is a pain. You have no
idea the lengths I went to so I could copy and paste that URL
to get you some possible business...
My website's pages are not meant to be viewed outside of the main frameset.
You don't have to send people to the particular pages directly, just send
them to the main URL. They'll see the Consulting link on the sidebar.
Gambit