Newsgroups : Borland : borland.public.delphi.internet.winsock : 2007 Mar : Re: Creating TCP server with blocking Indy components?
| Subject: | Re: Creating TCP server with blocking Indy components? |
| Posted by: | "Bo Berglund" (bo.berglu..@telia.com) |
| Date: | Fri, 23 Mar 2007 08:09:59 |
Thanks for your swift reply! :-)
I added extra comments below.
On Thu, 22 Mar 2007 17:27:50 -0800, "Remy Lebeau \(TeamB\)"
<no.spam@no.spam.com> wrote:
>
>"Bo Berglund" <bo.berglund@telia.com> wrote in message
>news:6j0603tt01oukngr9qr4sa17svo5h80kq0@4ax.com...
>
>> Now I see that these components won't live any longer
>
>Yes, they are still available. They are just not installed by default
>anymore.
>
>> Indy 9 is what is supplied by Borland with Delphi7,
>> but these components are blocking and I can't for the
>> life of me understand how I can ever get them to work...
>
>Have you looked at the demos yet?
Yes, I downloaded the demos for Indy9 and looked at the IdTCPDemo
But that is also when I got rather confused...
>Have you read the documentation yet?
Is there any docs besides the help file in Delphi7?
I tried that by putting Id components on my form and hitting F1. But I
soon got out of sync because in many places I could not even
understand the wording....
>
>> So I am required to build a TCP server, which will listen on two
>> ports, one is a "command" port and the other is a "state" port.
>
>Use TIdTCPServer. You can configure both ports with one component,
>via its Bindings property. Or you can use a separate TIdTCPServer for
>each port.
OK, I will look for help on "Bindings" then.
>
>> On the main port the tool will connect to me and I am required
>> to send back a command that basically tells the tool to also connect
>> to the state port.
>
>That is easy enough to do in the TIdTCPServer's OnConnect event.
In the example of the server I found only some administrative actions
in the ServerConnect method:
GetMem(NewClient, SizeOf(TClient));
NewClient.DNS := AThread.Connection.LocalName;
NewClient.Connected := Now;
NewClient.LastAction := NewClient.Connected;
NewClient.Thread :=AThread;
AThread.Data:=TObject(NewClient);
try
Clients.LockList.Add(NewClient);
finally
Clients.UnlockList;
end;
How do I actually send something back to the client here?
>Everything you can do in TServerSocket can be done in TIdTCPServer as
>well.
I hope so, but when I read the introduction here:
http://www.swissdelphicenter.ch/en/showarticle.php?id=4
it talks a lot about the blocking ways and unix...
Is this the way to send the data:
AThread.Connection.WriteLn('Indy Zip Code Server Ready.');
What happens if I don't want to have the line endings (my data contain
line endings but are not ended by suc, there are many lines in a
packet?
>
>> It will do so and then send a connect data packet on the "state"
>> socket. After this it will wait for commands from me on the
>> "command" socket and send event data on the "state" socket.
>
>Also easy to do, using the TIdTCPServer's OnExecute event, or
>accessing its Threads property.
OK, so OnExecute is an event that gets fired when? As soon as some
data have arrived or when the complete chunk of data from the client
has arrived? Sometimes the data are sizeable, over the command channel
I can request data and this is then sent over the "state" channel and
can be many kilobytes (all in XML).
>
>> All data packets are strings formatted as XML (again dictade
>> by the tool maker).
>
>That makes no difference. Indy handles string data just fine.
Yes, but what about the packet ending? I understand that you must tell
Indy which character is the ending character of a message and in this
case there is none. The only close thing I have is the end tag (6
chars).
>
>> There is as far as I have seen no special termination character
>> because the end bracket (>) repeats many times in the message text.
>
>That is fine, as long as the XML is well-formed so all tags are closed
>correctly.
>
>> The closing tag of the XML string is what identifies the end of
>message:
>> </msg>. But this is a 6-char string....
>
>So?
So it is not a single character that can be specified as the ending
char like LF or CR....
>
>> The examples I have seen do not clearly show how the server
>> (my program) can *send* commands to the connected client
>> and retrieve the responses.
>
>The same way you send and receive anything else in Indy - via the
>various methods of TIdTCPConnection. TIdTCPServer maintains a
>separate TIdTCPConnection object for each client connection. Just
>make sure that your access to that object is thread-safe, as
>TIdTCPServer is a multi-threaded component.
Now we are etting to my point. :-)
How can I get hold of that object? Is it a property of AThread?
(AThread.Connection)???
>
>> Note that the examples do it the other way, a client connects to a
>> server and then sends some command that gets replied to by the
>server.
>
>That is not a requirement. Both ways are possible with Indy.
>
>> What methods on the server should I use to actually send a string
>> to the connected client and retrieve its response???
>
>Examples of doing what you are asking for have been posted many times
>before. Go to http://www.deja.com to search through Borland's
>archives, and go to news.adtozed.com to look through Indy's newsgroups
>(there are no archives, but past messages are still on the server).
I understand that it must have been asked many times since it breaks
away from the old socket handling.
But I have trouble formulating searches that do not turn up masses of
unrelated things. Will try this link today.
>
>> The client (the tool) is supposed to send packets of data on the
>> "state" socket at asynchronous intervals. Since Indy is blocking
>> and thus there are no events, how can I ever retrieve these messages
>> on the server side????
>
>Use the OnExecute event. Simply call any of the TIdTCPConnection
>reading methods in that event, and the event handler will wait for the
>requested data to arrive from that client. Because TIdTCPServer is
>multi-threaded, blocking the event of one client will not block the
>events of other clients.
Thanks, I think I got that from the demo actually because the server
is normally designed to act on received data. So OnExecute fires
whenever a packet arives or when a complte transfer has been done?
>
>> In the old days I would simply collect the incoming data in the
>> receive event and when the message is complete as determined
>> by the length of the data (binary transfers) or some termination
>> word, I would process the message.
>
>You can do the exact same thing with TIdTCPServer. so all you have to
>do is tell it what to read (ReadInteger(), ReadLn() with a terminator,
>etc) and Indy will handle all of the waiting and buffering for you.
I'll give it a try. But what I need to read is a complte string of an
XML messsage packet. No fixed data types and no terminating character
(see above).
>
>> Finally, my Indy with D7 is 9.0.10, must I upgrade in order to
>create
>> the TCP server outlined above?
>
>No. But you should upgrade anyway, as that is a very old release of
>Indy 9. The current Development Snapshot is 9.0.50.
>
Development snapshot sounds like an unstable beta. Can it be used also
for production code?
Final question (forgot it yesterday):
This server must not allow more than one client to connect in order
not to mix up the machine tools. How can I separate them by
disallowing a connect if one is already established?
/Bo