Re: How do I tell an object to free up an owned object from thta object itself?

From: David Reeve (dree4456_at_big-pond.net.au)
Date: 10/04/03


Date: Sat, 04 Oct 2003 12:36:58 GMT


"Bo Berglund" <bo.berglund@telia.com> wrote in message
news:er2qnvcqasiehaiatrljpfqbgb1ujh0l9t@4ax.com...

OK ... I'm pretty sure I understand the problem. However, explaining it
without waving my arms about is going to be difficult. I have a map of
ScktComp.pas which I built up from many hours of stepping the code. I'll
tidy it up one day so I can put it up for others to see. For the moment,
apologies to the ng for the long post.

The root of the problem is that you are grabbing the socket passed in the
OnClientConnect event and messing with it. It is closely coupled to, and
managed by the TServerWinSocket instance, which is referenced by the socket
property of your top level TServerSocket. If you intercept its OnSocketEvent
eventhandler, then you break this connection with the inevitable result that
client-end connections will be left hanging and so on.

The TServerSocket wraps a TServerWinSocket which implements the basic
server functionality, ie the ability to manage simultaneous client
connections. Let's forget TServerSocket for the moment except to note that
its main purpose is the hide the complexities of swapping between blocking
and non-blocking modes, and concentrate on TServerWinSocket. From now on
I'll refer to the TServerWinSocket as the Server. In the non blocking mode,
the OnClientxxxx events of this Server are mapped to the outer wrapping
object.

Staying with the non blocking mode, on a call to Open, the ServerSocket
creates a thread of execution which listens for incoming connections at the
designated port. When a connection is detected, the Server creates a
TServerClientWinSocket object within the context of the main thread and
furnishes this with a physical socket it gets from the OS. This new object I
will refer to as a ClientConnection. ClientConnections are windowed, and
communicate with the underlying sockets layer by messaging.

For every new ClientConnection, a reference to it is added to a connection
list held by the Server and, ** most importantly**, the OnSocketEvent of
the ClientConnection is linked to a handler in the the Server. When a client
disconnects, the ClientConnection object is destroyed, its physical socket
relinquished to the OS, and its reference removed from the connection list.
Now once the Server has finished with these events arising from the
underlying sockets, they are passed, with some filtering and crossmapping,
to the events you know and love at top level TServerSocket.

One of the causes of confusion is the fact that both the Server object and
the ClientConnection object have TCustomWinSocket as their ancestor, and it
is this class that contains the bulk of the functionality. When you are
stepping code, it is a constant hassle to keep track of whether you are in a
Server object or a ClientConnection object as it is the same physical code.

So what is happening is the following.....
When the client connects....
    ClientConnection.FOnSocketEvent := Server.HandleClientSocketEvent
When you handle the OnClientConnectEvent.....
    ClientConnection.FOnSocketEvent := Bo'sObject.HandleClientSocketEvent
And the Server is basically broken :-)

> A) Yes, it is possible to call Self.Free from within the handler
> object itself in the SocketEvent method if a disconnect is detected.
>
> B) But I cannot do the FSocket.Free in this destructor. It causes an
> access violation. So I left that for the TServerSocket to handle.
>

Makes sense, your FSocket is a reference to a ClientConnection object, and
another reference to it will exist in the Server's connection list. When the
latter closes an attempt will be made to free it.

> C) I tested running a sequence of connect/disconnect from the client
> (clean, without forcing the application to exit). I had added a
> function to the server object to count the connections and list the
> client address for those connections that were active. Results:
> - The connections list accumulates over time. It does not look like
> the TServerSocket frees up sockets that are no longer in use.
> - The connections associated with clients that were forcibly closed
> (for example in Delphi debugger by stopping the program) are listed
> with active connections.
>

Makes sense. You have broken the link between the Server object and every
new ClientConnection object **after** the reference to the new object has
been added to the Server's connection list.

> D) So I had to add a server side timer that every 15 seconds runs
> through the connections list and frees all sockets that are not
> connected.
>

Yep.... the connection list is valid, so provided you don't free them in
your handler, this will work. BUT you shouldn't need to do this :-)

> E) A strange thing is the following:
> If I stop listening (TServerSocket.Close) then all client sockets are
> disconnected. I can thus not have the server listen for a given time
> and allow connections, then stop listening but still let the already
> connected clients continue communicating. Strange, this makes it more
> difficult to set an upper limit on the number of clients allowed.
>

Not strange. Quite understandable as the Server will work through its
connection list, which will be valid in so far as the ClientConnection
objects exist, though maybe not connected. The Server object controls the
lifetime of its ClientConnections. It doesn't make sense to allow
connections to live on without their controller. Well not as far as this
architecture is concerned.

> Finally, referring to one of your items:
> No, I dont't keep a list of created handlers in the server. They are
> just created in the OnClientConnect and are allowed to live
> independent lives. But the owner is the server object and they are
> descendants of TComponent so behind the scenes I guess some sort of
> list is kept nevertheless....
>
No problem here. TServerSocket ultimately descends from TComponent, and thus
your handler objects will be inserted in its component list on creation, and
will be freed when the TServerSocket is destroyed.

Dave



Relevant Pages

  • Re: How do I tell an object to free up an owned object from thta object itself?
    ... It seems that you advocate leaving all of this at the server level, ... >property of your top level TServerSocket. ... When a connection is detected, ... >For every new ClientConnection, a reference to it is added to a connection ...
    (comp.lang.pascal.delphi.misc)
  • Re: SBS 2003 IIS BASED SERVICES FAIL INTERMITTENTLY
    ... If I read your post correctly, you have a switch where the SBS ... Run DHCP server on your SBS, and set all client machine nics to dynamic. ... Once you have your nics configured, run the Connect to the Internet wizard, ... QUESTION1 - what is REFUSING CONNECTIONS? ...
    (microsoft.public.windows.server.sbs)
  • Re: SBS Exchange 2003: too many "Current Sessions" opened
    ... So far everything is good and now I'm just monitoring my exchange. ... get the SMTP service to stop hanging in the first place. ... won't have dead connections. ... work for now until I put into production new server hardware with sbs 2003 ...
    (microsoft.public.windows.server.sbs)
  • Re: SBS Exchange 2003: too many "Current Sessions" opened
    ... You really should go through the steps I posted and get the SMTP service to stop hanging in the first place. ... You'll be happier, you won't be clubbing your server every day with a kill script, and you won't have dead connections. ... You do *not* need to restart the server, ...
    (microsoft.public.windows.server.sbs)
  • Access 2007->SQL Server2005 "connection was forcibly closed",GNE 1
    ... I have a very big problem connecting an SQL ... changing number of clients using the SQL Server with this frontend at the ... connection pooling or if these connections are separated connections). ...
    (microsoft.public.sqlserver.connect)