Closing a TCP Asynch socket C#

I have a TCP socket application based on examples of asynch socket programming available on Microsoft site and an example on Code Project.  
My client is a GPRS based device which does not generally do a clean close on the TCP connection.   I need to remove these idle connections on my TCP server.  Am maintaining a hashtable in the server that keeps a record of the unique unitID sent by the client and the associated socket.  When the client reconnects -I need to course through the hashtable and close the socket related with the previous client ID and remove the entry in the hashtable and add this new entry with the current socket.  
My question is how to cleanly and surely remove a socket and how to manage the hashtable while doing so

My code is as follows

private bool removePrevSocketIfPresent(Hashtable hashTableUnits, long unitID)
        {
            bool allWEll = false;
            SocketAsyncEventArgs tempSocketToremove;
            DataHoldingUserToken tempTokenToRemove;
           //locking the hashtable for the whole operation
            lock (TRInitModule.hashTableUnits.SyncRoot)
            {
                bool markForRemoval = false;
                foreach (DictionaryEntry entry in TRInitModule.hashTableUnits)
                {
                    Int64 currentUnitID = Convert.ToInt64(entry.Key);
                    if (currentUnitID == unitID)
                    {
                        try
                        {
                            tempSocketToremove = (SocketAsyncEventArgs)(entry.Value);
                            tempTokenToRemove = (DataHoldingUserToken)tempSocketToremove.UserToken;
                            tempSocketToremove.SocketError = SocketError.OperationAborted;
                            tempSocketToremove.AcceptSocket.Shutdown(SocketShutdown.Both);

                            //is the above line enough or do I need to do the below lines too?
                           // tempSocketToremove.AcceptSocket.Close();
                           // tempTokenToRemove.Reset();
                            //if (tempTokenToRemove.theDataHolder.dataMessageReceived != null)
                            //{
                            //    tempTokenToRemove.CreateNewDataHolder();
                            //}
                         markForRemoval = true;
                            
                                Console.WriteLine();
                                Console.WriteLine("One socket removed, count is = " + TRInitModule.hashTableUnits.Keys.Count);
                            allWEll = true;
                        }
                        catch (Exception eRT)
                        {
                            allWEll = false;
                            Console.WriteLine("ERROR IN  REMOVE ITEM  " + eRT.Message);
                        }

                    }
                    else
                    {
                        markForRemoval = false;
                    }
                }
                if (markForRemoval)
                {
                    TRInitModule.hashTableUnits.Remove(unitID);
                }
            }
            return allWEll;
        }

Open in new window

MILIND_JOGAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

ambienceCommented:
For one, this defeats the purpose of a dictionary

                foreach (DictionaryEntry entry in TRInitModule.hashTableUnits)
                {
                    Int64 currentUnitID = Convert.ToInt64(entry.Key);
                    if (currentUnitID == unitID)

Open in new window


This is how it should be

if (TRInitModule.hashTableUnits.ContainsKey(unitID))

Also, "AcceptSocket.Shutdown(SocketShutdown.Both);" will try to flush buffers and most likely wont do anything if the socket has  been idle for some time. You should call Socket.Close() because that would free the resources associated with the socket. In fact, you may choose not to call Shutdown() if a client will only establish one connection at a time and is found reconnecting.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
MILIND_JOGAuthor Commented:
Please explain why Socket.Shutdown() is not needed.  

Also, once I know that the hashtable contains the unitID - I need to first close the socket with that key - so how do I get to that socket without running a foreach loop.

Thanks for your help though.
0
ambienceCommented:
Shutdown() is needed to make sure any pending data is received and sent, but since your device is "re-connecting" it wouldnt work since its establishing a new connection. You call shutdown in following scenario for example

socket.send(.......)
socket.shutdown()  -> make sure previous send is completed
socket.close()

-

This is how you should get the socket for dictionary.

var socketToRemove = TRInitModule.hashTableUnits[unitId];
0
Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

MILIND_JOGAuthor Commented:
I also need to check for idle sockets ( more than 5 minutes) and remove them.  Which is the best property to use to check for idle sockets?
0
ambienceCommented:
Well, a simple way is to keep a timestamp with the device specific data, like say

DateTime mLastActivityTime;

Update this every time you receive anything from the device.

You can then have a separate thread run at regular intervals to run over all connected devices and close those been idle for over 5 minutes.
0
MILIND_JOGAuthor Commented:
Wow that means I am on the right path. I have done just that.  Please tell me if the closing is alright is code below. I have  a list of all sockets plus a hashtable with unitID as key and the current live socket as I need to be able to send specific commands to the unit from time to time.  

 int listcount4 = Program.listOfSockets.Count;
                SocketAsyncEventArgs[] array4Purge = new SocketAsyncEventArgs[listcount4];
                Program.listOfSockets.CopyTo(array4Purge);

                foreach (SocketAsyncEventArgs socket4 in array4Purge)
                {
                    theUserTokenHere = (DataHoldingUserToken)socket4.UserToken;
                    //unitInKey = theUserTokenHere.unitID;
                    double timeSincePrevData = calcTimeInterval(theUserTokenHere);
                    if (timeSincePrevData > 0.8)
                    {
                        socket4.SocketError = SocketError.NotConnected;
                        socket4.AcceptSocket.Shutdown(SocketShutdown.Both);
                        Program.listOfSockets.Remove(socket4);
                        if (TRInitModule.hashTableUnits.ContainsValue(socket4))
                        {
                            lock (TRInitModule.hashTableUnits.SyncRoot)
                            {
                                TRInitModule.hashTableUnits.Remove(socket4);
                            }
                        }
                    }
                }

Thanks !!
Milind
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
TCP/IP

From novice to tech pro — start learning today.