Thanks Vadmyst,
I solved my issue and it actually didn't have anything to do with
Outstanding Begin Receives. I will explain after quickly responding to point
#2.
#2:
I'm glad that .Net 2.0 throws an exception if you Shutdown both or receive.
It's interesting that prior to 2.0, Microsoft recommended shutting down both,
but this does not make any sense because you wouldn't be able to receive the
close handshake from the client. Greath, thanks for that tidbit of
information. We have 2.0, but I am going to wait a bit before migrating to
production environment:->
My main issue is that my objects used during the connection were not being
GC'd. I thought I had modelled each reference in a simple application and it
should that memory should be released. The only other thing that could have
held on to it was a state object (which also held a refernce to my objects)
be held by the OS which would root everything. I was wrong about this
assumption and overlooked something that would have taken me a while to
figure out if it weren't for SciTech's Memory Profiler. What's really cool
about the profiler is that you can do differences between heap snapshots and
also it will show you were an object is rooted. It only took me five mitues.
If you haven't used it before, then I would recommend getting it. I will
explain my structures and then the problem.
TCPServer - This has a hashtable that holds TCPServerClient.
TCPServerClient - Wrapper Socket class for the socket communicating with
client. It holds a reference to TCPServer (for sending data and passing a
reference to itself when application wants to send data) and
IAppProtocolProcessor.
IAppProtocolProcessor - An application programmer creates a class that
implements the interface (OnAccept, OnReceive, OnDisconnect, OnTimeout).
When OnAccept is called, a reference to TCPServerClient is passed and the
implement class stores a refernce to it in order to Send data among other
things. This class also implements a static method based on the
CreateAppProtocol delegate. This delegate is passed into the TCPServer
constructor so that it can create an instance in the AcceptCallback.
So there is a circular reference between TCPServerClient and
IAppProtocolProcessor, the TCPServerClient has a reference to TCPServer, and
the TCPServerClient instance is referenced in the TCPServer hashtable. When
I close a connection, I simply remove the TCPServerClient form the hashtable.
My first worry was that the refrence form TCPServerClient up to TCPServer
was causing the problem because TCPServer is long-standing. This wasn't the
issue at all and I successfully modelled it. My problem was that in the
TCPServerClient, the timer was holding a reference to the
IAppProtocolProcessor's OnTimeout callback. During the connection close, I
stop the timer but do not remove the reference, and since this his an OS
resource it is rooted. It wouldn't have dawned on me to look there; thank
God for Memory Profiler tools (or actually, thank SciTech:->).