Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Detect Server disconnect using TTCPClient component

1,326 views
Skip to first unread message

Christopher Chuah

unread,
Feb 2, 2004, 9:00:47 PM2/2/04
to
Hi
I am having a problem in detecting Server closes the connection using the
TTCPClient component.

In the server side, i am using the TServerSocket.
On the client side, i am using TTCPClient, Connection Mode is Blocking. When
the client is connected to the Server using TCPClient1.connect, the event
OnConnect will be triggered to inform that the connection is connected.

However, when ServerSocket1.close is executed, there is no notification of
event to state that the connection is close. Please advise on how to detect
the closing of server connection.

Thanks
Chris


Paul Nicholls

unread,
Feb 2, 2004, 9:46:37 PM2/2/04
to
I think their are only 2 ways to detect a server disconnect (I could be
wrong though <G>):

1. the server sends a quit message to each client when disconnecting
2. the client sends 'stay alive' packets every now and then to the server
and detects if it fails during a send...

"Christopher Chuah" <cch...@tycoint.com> wrote in message
news:401f...@newsgroups.borland.com...

Remy Lebeau (TeamB)

unread,
Feb 2, 2004, 10:34:28 PM2/2/04
to

"Christopher Chuah" <cch...@tycoint.com> wrote in message
news:401f...@newsgroups.borland.com...

> However, when ServerSocket1.close is executed, there is


> no notification of event to state that the connection is close.

There is not supposed to be one. You will just have to wait until the next
time you actually access the socket in order to detect if it is still
connected or not. Typically, that is done in a timely fashion by simply
sending keep-alive data back and forth every so often so that each end can
determine whether the other end is still there.


Gambit


Martin James

unread,
Feb 3, 2004, 4:39:40 AM2/3/04
to
> There is not supposed to be one. You will just have to wait until the
next
> time you actually access the socket in order to detect if it is still
> connected or not. Typically, that is done in a timely fashion by simply
> sending keep-alive data back and forth every so often so that each end can
> determine whether the other end is still there.

Are you sure? I'm sure that I used to get an exception if a managed
disconnect was performed by the server.

Rgds,
Martin


Remy Lebeau (TeamB)

unread,
Feb 3, 2004, 5:46:25 AM2/3/04
to

"Martin James" <mjames...@dial.pipex.com> wrote in message
news:401f...@newsgroups.borland.com...

> Are you sure?

Yes.

> I'm sure that I used to get an exception if a managed
> disconnect was performed by the server.

Not for a blocking socket, no. Not unless you were actually accessing the
socket at a time that it had already been disconnected beforehand.


Gambit


Martin James

unread,
Feb 3, 2004, 6:12:02 AM2/3/04
to
>
> > Are you sure?
>
> Yes.
>
> > I'm sure that I used to get an exception if a managed
> > disconnect was performed by the server.
>
> Not for a blocking socket, no. Not unless you were actually accessing the
> socket at a time that it had already been disconnected beforehand.
>

Hmm.. I will have to look over my old code. I was 99% sure that a blocked
read call would except if the server disconnected. I remember writing code
that attemted to reconnect after a sleep if a disconnect exception ocurred.
My apps would turn the status bar red & display 'server has disconnected' as
soon as I shut down the server.

I will have to check to see how I did it.

Rgds,
Martin


Remy Lebeau (TeamB)

unread,
Feb 3, 2004, 2:34:38 PM2/3/04
to

"Martin James" <mjames...@dial.pipex.com> wrote in message
news:401f...@newsgroups.borland.com...

> Hmm.. I will have to look over my old code. I was 99% sure


> that a blocked read call would except if the server disconnected.

Of course if you are actually in the middle of a call at the time of the
disconnect, then yes, it will error. That is not the issue I have been
referring to. If your socket code is idle at the time, not reading from or
writing to the sockt at the time of the disconnect, then you won't detect
the disconnect until the next time you access the socket again.


Gambit


Martin James

unread,
Feb 3, 2004, 5:10:50 PM2/3/04
to

"Remy Lebeau (TeamB)" <gambit47...@no.spam.yahoo.com> wrote in message
news:401ff61e$1...@newsgroups.borland.com...

Hmm.. since Javier was using blocking mode, I assumed that a read call would
be outstanding nearly all of the time that the client was connected. This
may not be the case, & so you may be right.

Rgds,
Martin

Remy Lebeau (TeamB)

unread,
Feb 3, 2004, 7:28:49 PM2/3/04
to
"Martin James" <mjames...@dial.pipex.com> wrote in message
news:4020...@newsgroups.borland.com...

> Hmm.. since Javier was using blocking mode, I assumed that
> a read call would be outstanding nearly all of the time that the
> client was connected.

That is a possibility, but certainly not a requirement.

Let's also not forget the other issue regarding disconnects - graceful vs.
premature. In a graceful disconnect, the closing end negotiates a
controlled shutdown with the other end. That way both ends know that the
disconnect is occuring and can react accordingly. In a premature
disconnect, the connection basically just disappears without any
notification at all. In such cases, the underlying socket stack may not
detect the condition for a long while after the disconnect occured. Until
the stack actually times out after awhile and starts failing operations on
the socket, higher level application code has no way of knowing whether the
socket is still alive or not, unless it has its own timeouts implemented
that is.


Gambit


Christopher Chuah

unread,
Feb 3, 2004, 9:16:17 PM2/3/04
to
Hi everyone.
After reading so much of replies. I am still not sure how to detect a
disconnect from the Server. I have a server module that does not send any
keep alive data to the client. Hence, i will not be able to implement any
time out or keep alive mechanism.
Hence, it is important for the client to know when the server has
disconnected or when the network is down. In my source code for the
TTCPClient (blocking mode), i use a timer to poll the TCPClient component to
wait for Data..

procedure TForm1.Timer1Timer(Sender: TObject);
var
l_buf : string;
l_count : Integer;
l_sockAddr : TSockAddr;
l_port : word;
begin
if not IdTCPClient1.Active then exit;
if not idTCPClient1.WaitForData(200) then exit;
l_buf := '';
setlength(l_buf, 8109);
l_count := IdTCPClient1.ReceiveBuf(l_buf[1], 8109);
l_buf := Copy(l_buf, 1, l_count);
ShowMessage(l_buf);
end;

When the Server disconnects, the WaitForData return FALSE and there is no
way for me to detect the disconnection. I use this method becos the
ReceiveBuf is a blocking call. It will wait and wait. Should I use a thread
for the ReceiveBuf?

Please advise.

Thanks
Chris


"Remy Lebeau (TeamB)" <gambit47...@no.spam.yahoo.com> wrote in message

news:401f1515$1...@newsgroups.borland.com...

Remy Lebeau (TeamB)

unread,
Feb 3, 2004, 10:10:28 PM2/3/04
to

"Christopher Chuah" <cch...@tycoint.com> wrote in message
news:402056e3$1...@newsgroups.borland.com...

> After reading so much of replies. I am still not sure how
> to detect a disconnect from the Server.

The answer is simple - read from or write to the socket and see if it fails.

> I have a server module that does not send any keep alive data to the
client.

That is not exactly a very good design choice if you are writing your own
protocol. Keep alives are very handy when you can use them. If you are
expecting data within so much amount of time, and nothing comes, just close
the socket regardless if you think it is still alive or not.

What kind of module is it exactly? The module doesn't have to send data for
you, you can always send it yourself manually.

> Hence, i will not be able to implement any time out or keep alive
mechanism.

Then you are going to find it very difficult to reliably detect the
disconnect otherwise.

> Hence, it is important for the client to know when the server
> has disconnected or when the network is down.

You said that you are using blocking sockets. Thus, you need to access the
socket in some manner in order to determine that.

> if not IdTCPClient1.Active then exit;

Wait a minute. You said you were using TTCPClient. Are you actually using
Indy's TIdTCPClient instead? Your naming conventions are very confusing.

> When the Server disconnects, the WaitForData return FALSE
> and there is no way for me to detect the disconnection.

Did the server disconnect gracefully to begin with? Assuming WaitForData()
is using WinSock's select() function internally, then it should have
returned True instead of False if the server had disconnected gracefully.
In which case, ReceiveBuf() would indicate that 0 bytes were received. The
combination of WaitForData() returning True and the actual reading returning
0 means that a disconnect occured.

If the server did not disconnect gracefully, then as was explained in my
previous reply, there is simply no way you can detect the disconnect until
the underlying socket stac itself times out and invalidates the socket and
reports errors. Until then, it is going to keep returning successful
responsesto operations even though the server is long gone, simply because
it does not know yet that it is gone.

> Should I use a thread for the ReceiveBuf?

You could. You should still use WaitForData() to detect the disconnect even
in that scenerio, though.


Gambit


Christopher Chuah

unread,
Feb 4, 2004, 2:02:46 AM2/4/04
to
Hi Gambit
Sorry for the confusion. I was using the TTCPClient component. As for the
naming convention, i was switching between Indy component and TTCPClient
component.
All the while, i was using the TServerSocket and TClientSocket. That has no
problem in diconnection nor reading data. It was a very simple and easy
component to use. Very straight forward.
However, my company wants to port the code to Kylix and Kylix don have
TServerSocket and TClientSocket component, i have to try out TTCPCLient and
TIdTCPClient components.

Now, back to my story...
This is a testing program where i was trying to determine which component is
easier to use. It seems that both are not as easy to use as compared to
TClientSocket component. I think i need to write Threads or Timers to read
from the socket.

What is the timeout value for the underlying socket stack? Can i modify that
value to make it shorter so that i can reconnect to the server as soon as
possible.

In my example program, the Server module uses TServerSocket. When the main
form is created, it called ServerSocket1.open. When the main form is closed,
it called ServerSocket1.close;

The client program uses the timer to read the data from the socket. When i
close the main form of the Server module, the WaitForData in the Client
program return FALSE.

I tried to use the Select() function in the Timer function but even if the
Server is disconnected, the result returned by Select() still remains as
TRUE.

procedure TForm1.Timer1Timer(Sender: TObject);
var
l_buf : string;
l_count : Integer;
l_sockAddr : TSockAddr;
l_port : word;

l_RState, l_WState, l_EState : PBoolean;
l_result : boolean;
begin


if not IdTCPClient1.Active then exit;

new(l_RState);
New(l_WState);
New(l_EState);
l_result := Select(l_RState, l_WState, l_EState, 100);
if (l_EState^) or (not l_result) then
ShowMessage("Error")
Dispose(l_RState);
Dispose(l_WState);
Dispose(l_EState);


if not idTCPClient1.WaitForData(200) then exit;
l_buf := '';
setlength(l_buf, 8109);
l_count := IdTCPClient1.ReceiveBuf(l_buf[1], 8109);
l_buf := Copy(l_buf, 1, l_count);
ShowMessage(l_buf);
end;


Is there any demo programs or examples that i can reference to? Then i can
try to see how to use the TTCPClient and TidTCPClient components.


Thanks
Chris

Remy Lebeau (TeamB)

unread,
Feb 4, 2004, 4:26:42 AM2/4/04
to

"Christopher Chuah" <cch...@tycoint.com> wrote in message
news:4020...@newsgroups.borland.com...

> All the while, i was using the TServerSocket and TClientSocket. That has
no
> problem in diconnection nor reading data. It was a very simple and easy
> component to use. Very straight forward.

You were probably using them in non-blocking mode. That works very
differently then blocking mode does.

> However, my company wants to port the code to Kylix and Kylix
> don have TServerSocket and TClientSocket component, i have to
> try out TTCPCLient and TIdTCPClient components.

Use Indy. The native CLX socket components are poorly implemented and have
several bugs/issues that have been reported.

> I think i need to write Threads or Timers to read from the socket.

Threads are not strictly required, but for blocking sockets they do help
make code management easier.

> What is the timeout value for the underlying socket stack?

It depends on the vendor's implementation. There are also ways, via
setsockopt() and ioctlsocket() and such, to configure various aspects of the
stack programmably.

> Can i modify that value to make it shorter so that i can
> reconnect to the server as soon as possible.

As far I know, there is no way to set the timeout for connecting
specifically. What you can do, however, is use a separate thread to
disconnect the socket while it is connecting if your own timeout value
elapses.

> When i close the main form of the Server module, the
> WaitForData in the Client program return FALSE.

Then the server is not closing down correctly. WaitForData() has to return
True on a disconnect. Assuming that it is using select(), that is, which it
must likely is. That behavior or select() is dictated by the socket API
specifications.

> I tried to use the Select() function in the Timer function but even if
> the Server is disconnected, the result returned by Select() still
> remains as TRUE.

As well it should. Please read the API documentation for select(). It
tells you that when the socket is disconnected gracefully, select() returns
that the socket enters into a readable state. You then need to call recv()
(or whatever component code is wrapping recv()) and see if it returns 0. If
it does, the socket has been disconnected.

> l_result := Select(l_RState, l_WState, l_EState, 100);

<snip>


> if not idTCPClient1.WaitForData(200) then exit;

There is no need to call WaitForData() if you are calling Select() directly.
They do the same thing.

> l_count := IdTCPClient1.ReceiveBuf(l_buf[1], 8109);

You are not testing the return value of ReceiveBuf() to see if it is 0 or
not. You need to do that.


Gambit


Martin James

unread,
Feb 4, 2004, 4:42:02 AM2/4/04
to

> Is there any demo programs or examples that i can reference to? Then i can
> try to see how to use the TTCPClient and TidTCPClient components.

I have a little TidTCPClient demo I wrote ages ago. It doesn't do much -
it's just a text terminal, but it does detect managed disconnects and then
repeatedly retries to connect. I'll post it to 'attachments'. Rt-click on
the status bar to get the config form that allows you to set the host, port
etc. The config form unit has a thread to perform the reading.

I'm sure there are bugs sisnce I wrote it ages ago, but I jut tried it & it
seems to work against an FTP server. There is some other crap in the demo
but it's the 'CthreadForm' unit that contains the relevant stuff you might
want to look at.

Rgds,
Martin


Christopher Chuah

unread,
Feb 4, 2004, 9:06:53 PM2/4/04
to
Hi Martin
Could i have a look at the demo programs that u have written. At least there
are some references that i could start with.

Could u send me a email to chua...@yahoo.com.
Many Thanks
Chris

"Martin James" <mjames...@dial.pipex.com> wrote in message
news:4020...@newsgroups.borland.com...
>

Christopher Chuah

unread,
Feb 5, 2004, 5:30:32 AM2/5/04
to
Hi Everyone.
I think i need yr advise.
I have a server module that sends data in this format
<Header><Data>
Within the header, it will specify the length of the data.
Hence, when i am trying to use the Indy Component, version 8, i can't use
the Readln as it needs a terminator character. In that Data, it can have
different type of characters. Hence, i can't really use Readln.
How am i able to read the data from the socket?
I have tried the following:
CurrentReadBuffer.. this will return the string. However, it seems to hang
the main application.
ReadBuffer.. a blocking type of call. Should i use the idAntifreeze in the
application?

How should i go about reading this type of data from the socket?

Thanks
Chris


Martin James

unread,
Feb 5, 2004, 12:28:54 PM2/5/04
to

> Could i have a look at the demo programs that u have written. At least
there
> are some references that i could start with.

Download 'Indy TCP client demo' from 'borland.public.attachments'.

Rgds,
Martin


Remy Lebeau (TeamB)

unread,
Feb 5, 2004, 3:10:04 PM2/5/04
to

"Christopher Chuah" <cch...@tycoint.com> wrote in message
news:40221c3a$1...@newsgroups.borland.com...

> Hence, when i am trying to use the Indy Component, version 8,

That is an outdated version that is no longer supported. You should
consider upgrading to Indy 9.

> i can't use the Readln as it needs a terminator character.

Use ReadBuffer() instead. Your header should be fixed size so that you
specify the same size to ReadBuffer() each time, and then when you extract
the data length from the header, you can pass that length to the next call
to ReadBuffer() to get the data.

> In that Data, it can have different type of characters.

That makes no difference to ReadBuffer() at all.

> I have tried the following: CurrentReadBuffer..

Do not use that, it is not suited for what you are asking.


Gambit


Christopher Chuah

unread,
Feb 5, 2004, 8:09:39 PM2/5/04
to
Hi
Is Indy 9 supported in Kylix 3?
Another main reason for using Indy is that my source code can be ported over
without much changes.
From the Indy web site, it states that Indy 9 is use for Kylix 1 and 2 but
not 3. Is that true?

Thanks
Chris

"Remy Lebeau (TeamB)" <gambit47...@no.spam.yahoo.com> wrote in message

news:4022a166$1...@newsgroups.borland.com...

Chad Z. Hower aka Kudzu

unread,
Feb 6, 2004, 2:07:41 PM2/6/04
to
"Christopher Chuah" <cch...@tycoint.com> wrote in
news:4022ea3e$1...@newsgroups.borland.com:
> Is Indy 9 supported in Kylix 3?
> Another main reason for using Indy is that my source code can be ported
> over without much changes.
> From the Indy web site, it states that Indy 9 is use for Kylix 1 and 2
> but not 3. Is that true?

It works fine in 3 too. Which page still lists just 1 and 2?


--
Chad Z. Hower (a.k.a. Kudzu) - http://www.hower.org/Kudzu/
"Programming is an art form that fights back"

Want to keep up to date with Indy?

Join Indy News - it free!

http://www.atozed.com/indy/news/


ELKNews - Get your free copy at http://www.atozedsoftware.com

Christopher Chuah

unread,
Feb 8, 2004, 9:46:34 PM2/8/04
to
Hi Chad

Here is the URL : http://www.indyproject.org/download/Files/Indy9.html

This section......which i just cut and paste from the web site..
Indy 9.0 Downloads
Releases
Note: These contains source files only with no installation support or
precompiled binaries. If you need further help, please see the support page.

a.. 9.0.14 Source code distribution
a.. ZIP - Windows distribution for Delphi 4, Delphi 5, Delphi 6, Delphi
7, C++ Builder 4, C++ Builder 5, C++ Builder 6
b.. TGZ / RAR - Linux distribution for Kylix 1, Kylix 2

Here, you see that Kylix 3 is not stated. Hence it is assumed that Kylix 3
is not supported by 9.0.14.

Thanks
Chris

"Chad Z. Hower aka Kudzu" <cp...@hower.org> wrote in message
news:Xns9487D6E...@127.0.0.1...

0 new messages