Recommended Posts

Hi all,
im developing a TCP server component and currently in the design stage.
My concern is as follows. The server object will keep a collection of client objects which each keep track of a connected socket. If I pass a client object back to the user, and subsequesntly the client object is deleted in a seperate thread (lets say the connection is closed) and then the user trys to access the client object.. that would cause a memory exception. My alternative that i can see is that I can pass back a reference to the client object to the user (like an index for where the client is in the list of client objects, OR the socket number related to the client). I can also see problems with that thought because...
1) If you use an array to store the collection of clients and pass the index number to the client then its limited in max number of clients (unexceptable) and also in theory if a client index is passed to the user and then in another thread the client disconnects and another connects and takes the place of the old client then the user will be using the wrong client without even knowing !
2) If you have some kind of linked list and just return the socket number related to a connection to the user, then when accessing the client object the server component would have to look through all the clients to find the client whos socket matched the one passed in by the user ! which if there are a large number of clients will take ages.. and again if a client disconnects and a new one connects then the new client can have the same socket number as the closed connection !
HOW should I go about stoping these problems ??
thanks for any advice
Tim

0

Share this post

Link to post

Share on other sites

Say you have a class called CClientConnection. All commands coming from the client are routed through this object through some sort of 'handler' function. NOTE: This is only for a connection-oriented communication stream. Thus state can be saved on the server while communication packets flow between the two. {NOTE: I use IOCPorts and needed no list of CClientConnection(s) since their pointers were passed with the IOCP packets. In your case, this may not be the case.)

If using UDP for your communications, you will have to send an ID of some sort from the client to the server with every packet since UDP is a stateless protocol. Have the server assign a GUID to the connecting client during it's HELLO packet and respond with a HI INSERT_GUID_HERE. Then the server saves the GUID and the CClientConnection class in a map(quick lookup).

As far as timeouts go, in the non-UDP example, the server will notice the timeout and destroy the CClientConnection and all of it's associated state. In the UDP version, timeouts become a bit more difficult but still follow the same kind of semantics. Timeout on server, server removes the GUID and associated class object that is handling incoming commands from the client from the list of connected clients.

Hope I didn't add more chaos to the mix...

[edited by - LordShade on March 25, 2003 11:56:40 PM]

[edited by - LordShade on March 25, 2003 11:57:33 PM]

0

Share this post

Link to post

Share on other sites

quote:Original post by sleepytim My alternative that i can see is that I can pass back a reference to the client object to the user (like an index for where the client is in the list of client objects, OR the socket number related to the client).

If I get the question right, the problems are:1) generating a unique identifier per connection2) finding an item in a list using said unique identifier as key

Well, a random-generated number comes to mind for the key. As far as the organization of the items in the list, use STL''s map<> to store the items.

quote:Original post by sleepytim which if there are a large number of clients will take ages..

Don''t *overestimate* your computer''s networking capacity. Sending and receiving messages is far slower then searching through a list (and a map<>''d list for that matter).

Share this post

Link to post

Share on other sites

LordShade, Im using IOCP.. but the server could only not keep a list of clients if it was only ever responding to a message from a client which is very limiting.

cbenoi1, I had thought about a unique ID.. could simply and efficiently be done with a static integer in the class which is incremented and used each time the client class is created...

One problem would still be that because its multi threaded the application could return a client object and then in another thread delete the object, folled by the thread who has a reference to the now deleted object trying to use it. That said I guess it could be managed with a critical section, or a reference counter but i guess in multi threaded apps you cant totally avoid that problem because if you were very unlucky then the program could return the object, switch threads and delete the object, switch back and try to increment the reference count ! unless.. you have a list of reference counters and before you try to get the object you increment its counter and then get the object

Share this post

Link to post

Share on other sites

quote:Original post by wrathgame if you were very unlucky then the program could return the object, switch threads and delete the object, switch back and try to increment the reference count !

That's why you would:

(in the spawn new object function)1) create a new critical section2) InitializeCriticalSection()3) create a new object4) assign the CS to the object5) add the object to a global linked list, map, etc.6) return object

Then, in the deletion function,

1) enter the object's CS2) delete the object3) leave the CS4) DeleteCriticalSection()5) deallocate the memory used to store the CS

And in any other part of the code, enter the object's CS before messing with the object and leave after object manipulation is complete (in effect wrapping all object calls in a critical section):

1) enter the object's CS2) CS may have been deleted while we were waiting for ownership; does the object still exist? If so, continue; else, fail and return.3) manipulate object4) leave the object's CS

The slight downside to this scheme is that each object would require a pointer to store its critical section. However, everything would be synchronized, and the chance of thread conflicts dramatically reduced (perhaps to zero).

quote:unless.. you have a list of reference counters and before you try to get the object you increment its counter and then get the object

Unfortunately, this is prone to the same problem. What happens if the "get" thread decides it wants to fetch the object, a context switch occurs, a "delete" thread deletes the object, and another context switch puts the "get" thread back in control? If the reference counter was tied to the object, the thread is now accessing faulty memory. If the counter is stored in a table and somehow successfully incremented, the thread will retrieve faulty memory. You'd need critical sections somewhere to ensure that context switches don't occur at inopportune moments.