BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Indy/TCP - initiated by both ends?

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi Internet Winsock
View previous topic :: View next topic  
Author Message
David Henningsson
Guest





PostPosted: Mon Dec 20, 2004 3:44 pm    Post subject: Indy/TCP - initiated by both ends? Reply with quote




In most TCP protocols, there are one client that sends something and the server replies. In my app, I have to have communication in both directions, i e the server can (driven by another internal event in the server) send a packet, or the client can, driven e g by the user requesting a new view, request info from the server.

So I have specified and implemented a protocol that allows this kind of communication. However, with Indy (9.0.14) I find it hard to be able to be truly event driven in both ends.

On the server side, where each connection is a thread, I could do a loop like:

while not Terminated do begin
TCP.ReadFromStack(30 ms);
if TCP.InputBuffer.Size > 0 then
HandleIncomingData;
if NeedsToWrite then
TCP.Write(OutgoingData);
end;

However, this means that outgoing data has up to 30 ms delay, which is bad, and I guess lessing the 30 ms would probably start to eat CPU when you have lots of connections.

So, I wonder:

1. Is there a good way to know when data is coming in, using Indy, or does the blocking nature of Indy prevent this?

2. Could I set some kind of event from another thread to make ReadFromStack abort, before the timeout period has elapsed?

3. Can I make something using the socket handle and WSAAsyncSelect, or would that just mean more trouble?

4. Is there another brilliant solution I haven't thought of?

// David


Back to top
Martin James
Guest





PostPosted: Mon Dec 20, 2004 4:06 pm    Post subject: Re: Indy/TCP - initiated by both ends? Reply with quote



Quote:

In most TCP protocols, there are one client that sends something and the
server replies. In my app, I have to have communication in both directions,

i e the server can (driven by another internal event in the server) send a
packet, or the client can, driven e g by the user requesting a new view,
request info from the server.
Quote:

So I have specified and implemented a protocol that allows this kind of
communication. However, with Indy (9.0.14) I find it hard to be able to be

truly event driven in both ends.

It can be a bit awkward :)

What thread is 'internal event in the server' fired from? The thread that
fires this event can maybee write to the client directly. Whether this is
acceptable to your protocol is another matter. Since only one thread should
write at a time, you would need a CS or mutex lock on the write methods/s to
prevent problems with Winsock buffer corruption and/or violations of your
protocol.

Assuming two messages, one in response to client request and asembled
directly in the peer thread: 'clientReply', and one asynchronous message
from some oher thread: 'asynchronousMessage'

A CS could enforce the safe sending of:

clientReasynchronousMessageply

This may well not be friendly for your protocol, though some protocols based
on text chars can stand this, (eg. client request/response chars are all
<128, all asynchronous messages are 128
A mutex lock could enforce the sending of:

clientReplyasynchronousMessage

It would be nice if Indy allowed peer threads to wait on a socket *and* an
object/data queue at the same time, but AFAIK this is not directly
supported.

Rgds,
Martin



Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Mon Dec 20, 2004 8:59 pm    Post subject: Re: Indy/TCP - initiated by both ends? Reply with quote




"David Henningsson" <nil (AT) nil (DOT) se> wrote


Quote:
So I have specified and implemented a protocol that allows this kind
of communication. However, with Indy (9.0.14) I find it hard to be
able to be truly event driven in both ends.

Indy is not an event-driven asynchronous library to begin with. If you want
that, then you have to implement it manually. Each side would need its own
dedicated reading thread. When data arrives, the thread can process the
incoming data as needed. As for sending, you can send data from multiple
threads directly to the socket, as long as you are providing your own
synchronized access to the socket so that outgoing packets do not overlap
each other.

Quote:
On the server side, where each connection is a thread, I could do a
loop like:

while not Terminated do begin

Do not do that. The OnExecute event is already looped by the TIdTCPServer
internally. You should perform only a single iteration of the loop inside
your OnExecute code.

Quote:
if NeedsToWrite then
TCP.Write(OutgoingData);
end;

You do not need to do that. Your other threads can write directly to the
TCP socket without queing the data first.

Quote:
However, this means that outgoing data has up to 30 ms delay,
which is bad

Simply don't implement an outgoing queue, and you won't have that delay
anymore.

Quote:
I guess lessing the 30 ms would probably start to eat CPU when you
have lots of connections.

No, because the thread is sleeping during that 30 ms if there is no data
available to read.

Quote:
1. Is there a good way to know when data is coming in, using Indy, or
does the blocking nature of Indy prevent this?

Reading the socket is the only way to know when data actually arrives.

Quote:
2. Could I set some kind of event from another thread to make
ReadFromStack
abort, before the timeout period has elapsed?

No. The only way to abort ReadFromStack() prematurely is to disconnect the
socket.

Quote:
3. Can I make something using the socket handle and WSAAsyncSelect, or
would that just mean more trouble?


WSAAsyncSelect() forces the socket into non-blocking mode. Indy requires
the socket to remain in blocking mode.

Quote:
4. Is there another brilliant solution I haven't thought of?

There is nothing wrong with the threaded read approach. Just adjust your
code to get rid of the outgoing queue, and to provide synced access when
writing data from different threads to the same socket.


Gambit



Back to top
David Henningsson
Guest





PostPosted: Tue Dec 21, 2004 8:07 am    Post subject: Re: Indy/TCP - initiated by both ends? Reply with quote


Hello Gambit, and thanks for your answer.

If I understand you correctly, you say that

- only one thread can write at a time
- only one thread can read at a time
- but, one thread can write at the same time as another thread
reads, without any need for synchronisation. This must be
something special to the Indy TCP Connection Component, since
AFAIK every method call or property access to a component must
be synchronized in normal cases.

Does it matter whether it was the reading thread or writing thread that created the connection? Are there special methods I can or cannot use for writing when another thread is reading?

Quote:
I guess lessing the 30 ms would probably start to eat CPU when you
have lots of connections.
No, because the thread is sleeping during that 30 ms if there
is no data
available to read.

What I meant, was that if i reduce 30 ms to 2 ms, then there will be a lot of TCPServer iterations which probably would take some CPU time (even if they are very short), especially if there are lots of connections. However, if other threads can write, there is no need to lessen that delay.

Quote:
2. Could I set some kind of event from another thread to make
ReadFromStack
abort, before the timeout period has elapsed?
No. The only way to abort ReadFromStack() prematurely is to disconnect the
socket.

Can I do this as well from another thread? It could be useful when somebody shuts down the application and I'm stuck in readfromstack.

// David

Back to top
David Henningsson
Guest





PostPosted: Tue Dec 21, 2004 8:41 am    Post subject: Re: Indy/TCP - initiated by both ends? Reply with quote


Hello and thanks for your answer.

Quote:
What thread is 'internal event in the server' fired from?

Another one Smile Usually the main thread.

Quote:
Assuming two messages, one in response to client request and asembled
directly in the peer thread: 'clientReply', and one asynchronous message
from some oher thread: 'asynchronousMessage'

A CS could enforce the safe sending of:

clientReasynchronousMessageply

If I do like this in one thread:

EnterCriticalSection(foo);
TCP.Write('clientReply');
LeaveCriticalSection(foo);

and this in another:

EnterCriticalSection(foo);
TCP.Write('asynchronousMessage');
LeaveCriticalSection(foo);

....are you saying there is a possibility they are being
received by the client as clientReasynchronousMessageply?

// David

Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Tue Dec 21, 2004 9:46 am    Post subject: Re: Indy/TCP - initiated by both ends? Reply with quote


"David Henningsson" <nil (AT) nil (DOT) se> wrote


Quote:
- only one thread can write at a time
- only one thread can read at a time
- but, one thread can write at the same time as another
thread reads, without any need for synchronisation.

Correct.

Quote:
This must be something special to the Indy TCP Connection
Component

No. All socket programming is like that in general.

Quote:
since AFAIK every method call or property access to a
component must be synchronized in normal cases.

Not necessarily. Only those that invoke access to the GUI, or do not
provide their own synching internally.

Quote:
Does it matter whether it was the reading thread or writing
thread that created the connection?

No.

Quote:
Are there special methods I can or cannot use for writing when
another thread is reading?

Do not use SendCmd(), unless you sync all of your other reading/writing code
with it. SendCmd() performs its own reading internally, via GetResponse().

Quote:
No. The only way to abort ReadFromStack() prematurely is to
disconnect the socket.

Can I do this as well from another thread?

Yes. It is very common in socket programming to disconnect a socket from
one thread while another thread is performing a blocking operation on the
same socket. The blocked thread will receive an error immediately regarding
the socket becoming invalidated, which it can then handle accordingly.

Quote:
It could be useful when somebody shuts down the application
and I'm stuck in readfromstack.

Just deactivate the server/client. It already disconnects the socket, thus
terminating any threads that are still running.


Gambit



Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi Internet Winsock All times are GMT
Page 1 of 1

 
Jump to:  
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


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.