Newsgroups : Borland : borland.public.delphi.internet.winsock : 2006 Jun : Re: TCP client/server
| Subject: | Re: TCP client/server |
| Posted by: | "Remy Lebeau (TeamB)" (no.spam@no.spam.com) |
| Date: | Mon, 5 Jun 2006 17:43:46 |
"Jamie Dale" <j.dale@turboz.net> wrote in message
news:4484c870@newsgroups.borland.com...
> Remy, I code the way the online tutorials teach.
The online tutorials are not always accurate or up-to-date.
> My point is I'm just trying to show another easier (and easy to
> understand) way of solving the problem.
It is not a real solution, though. It is a hack that hides the underlying
problem, not fixes it.
> So why does the client raise the error then?
There is no way to know without debugging it further. Richard did not
provide enough details to diagose the problem fully.
> If you disconnect from the server, the client needs the try/except
> in any read or write situation to avoid that really annoying error
> message.
Only if the client is trying to continue reading from, or writing to, the
socket after it has been closed by the server. Which is usually a bug in
the client code for trying to keep accessing the socket in the first place.
Unless the server closed the socket prematurely, in which case the exception
is accurate and should not be ignored.
Like I said earlier, if his server code is adequately blocking, then there
is no reason for the exception to come from the WriteLn(). And it can't be
coming from the Disconnect(), either, because Disconnect() is specifically
coded NOT to throw that exception.
> I understand that but sometimes you want to forcefully disconnect
> a client - EG if they are not authorised to connect etc.
That is a completely separate issue. Of course the client should, and will,
receive the exception if the server actively closes the connection without
telling the client first. That is a very different scenerio that is not
related to the issue at hand.
> You are right - I forgot he is only writing and not reading lol. I suppose
> he could simply put his WriteLn statement into the try/except clause
> instead which would protect him from the error message when closing.
Only if the exception is coming from WriteLn() to begin with, which is
almost impossible in this scenerio unless the the server is not properly
waiting for all of the data from WriteLn() to arrive before then closing the
socket.
> I would say Indy being a pain in the grass is a good cause..
Indy is specifically designed to make heavy use of exceptions. Exceptions
are not errors, although they can be used to report errors. Exceptions are
a very OOP, and language-neutral, way to send notifications from one code
block to another without having to process a bunch of error conditions in
between just to decide how execution flow reaches each block. If you don't
like the way Indy is designed to work, then don't use it. The VCL also
makes heavy use of exceptions, but you use it anyway. So please don't knock
on Indy just because it follows the same kind of design principles.
> I've known many people have problems with this error
EIdConnClosedGracefully is not an error. It is a legitimate notification -
some peice of code tried to access the socket after it was closed.
> it's a pain because the server also suffers from the pesky error message
too.
As it should be. In fact, that is very common for servers, and is perfectly
normal behavior. Most servers (Indy and otherwise) are implemented to keep
accessing a socket until after the client disconnects. So
EIdConnClosedGracefully (amongst others) is raised to stop the server's
accesses of the socket. Indy servers handle EIdConnClosedGracefully
automatically. This is even documented in Indy's source code:
If this is a SERVER
-------------------
The client has disconnected the socket normally and this exception is used
to notify the
server handling code. This exception is normal and will only happen from
within the IDE, not
while your program is running as an EXE. If you do not want to see this,
add this exception
or EIdSilentException to the IDE options as exceptions not to break on.
From the IDE just hit F9 again and Indy will catch and handle the
exception.
If this is a CLIENT
-------------------
The server side of this connection has disconnected normaly but your
client has attempted
to read or write to the connection. You should trap this error using a
try..except.
The only time that does not happen properly is when user's own code
interfers with the server's normal behavior.
> It can be hard to get to the bottom of this error sometimes and
> frequently it doesn't even seem to have a cause.
It always has a cause, a very specific cause - accessing the socket for
reading or writing after a socket has been closed by the other party. That
is the only condition that can ever trigger EIdConnClosedGracefully.
> I know it is not the perfect 'Remy' method/standard
It has nothing to do with me. What I explain is how Indy is designed to be
used by everyone. If you don't use it properly, then expect problems to
happen.
> Yes/No lol, because like I said above, I've had the same error
> on the server side in the past too.
Like I said, it is normal to see it on the server side. It is supposed to
be seen on the server side. Indy servers handle it automatically.
> I've had problems in my own application where after my Client disconnects
> it still shows the "Connection Closed Gracefully" message even though the
> client disconnected itself.
The only way that can happen is if you try to access the socket after it has
been closed.
> I could find absolutely no reason for the application to still attempt a
> write operation (I always use the "If TCPClient.Connected" method
> so it will only write IF connected).
The Connected() method itself reads from the socket. The only way to detect
when a blocking socket has been closed is to read/write from it. Though
Connected() does prevent the EIdConnClosedGracefully exception from being
thrown by Connected() itself. But if you are checking Connected() before
all of your reading/writing, then there is no way you can ever get
EIdConnClosedGracefully unless the socket is closed while you are in the
middle of a read/write operation. In which case, raising
EIdConnClosedGracefully is the correct thing for Indy to do.
> There seemed to be no reason for it attempting to write other than
> TCPClient wanting to do so for some strange reason.
TIdTCPClient never does its own reading/writing. The only reading/writing
that is performed is in response to operations that your own code tells it
to do.
> I introduced the try/except clause and that was the end of the problem.
Hardly. You put a bandage on it, nothing more. You never fix the real
issues.
Gambit