"David Krmpotic" <david.krmpotic@no-no.si> wrote in message
news:2m5Xe.269$h6.88125@news.siol.net...
> Hello,
>
> I have a simple app with server (a bunch of singletons) and clients that
> connect to it.
> Each client gets a unique ID (some integer) upon connection and then pings
> the server regularily with it.
> if there is no ping for some time, server concludes that client has died
> (freeze, reboot) and releases its ID and any locks that client has put on
> rows in tables.
>
> The strange problem is that (if you look at the code),
> GetHostNameByClientID(int clientID) constantly returns null from some
> places... I found out that this hashtable - ID2HostName is somehow
different
> (?) in these calls than normal (referenced in Ping method for example). it
> is empty, although ping shows name of the host nicely. I further proved
that
> this is a different object be checkinh the return from GetHashCode().
>
> but when I put the declaration of the hashtable like this:
>
> internal static readonly Hashtable ID2HostName= new Hashtable();
>
> then it work! I don't know by what coincidence, but I stumbled upon this
> article
>
>
http://www.yoda.arachsys.com/csharp/singleton.html
>
> just few hours before experiencing this problem. I could imagine how this
> could happen in the example mentioned there, but not in my case.. well..
> maybe.. or obviously.. but I cannot explain it..
> so that means that I should use internal static readonly for all the
fields
> on my SAOS like that? or prepare myself for terrible surprises!
>
> thank you a lot for helping me clarify this strange thing.
>
> take care!
> David
>
> =========================================
>
> public class ConnectedClientsManager: MarshalByRefObject
> {
> private MyLib.UniqueIDGenerator uniqueIDGenerator = new
UniqueIDGenerator;
> private ID2AliveStatus = new Hashtable();
> private Hashtable ID2HostName= new Hashtable();
>
> private System.Threading.Timer checkForDeadClientsTimer;
>
> public ConnectedClientsManager()
> {
>
> //we check for dead clients every 10s
> //this means that dead client will be detected
> //10 to 20s after it dies. After a client dies,
> //this timer has to fire twice to detect it
> //first time it just sets Alive flag for all clients to false
> //and the next time it detects that it is still on file
> //(there was no ping in the meantime)
> int interval = 10000;
> checkForDeadClientsTimer = new System.Threading.Timer(new
> System.Threading.TimerCallback(CheckForDeadClients), null, interval,
> interval);
> }
>
> public int ClientConnected(string hostName)
> {
> lock(this)
> {
> int ID = uniqueIDGenerator.GenerateNewID();
>
> Console.WriteLine("Client " + hostName + " ("+ID+") connected!");
>
> ID2AliveStatus.Add(ID, true);
> ID2HostName.Add(ID, hostName);
>
> Console.WriteLine("Conn "+ID2HostName.GetHashCode().ToString());
>
> return ID;
> }
> }
>
> public void ClientDisconnected(int clientID)
> {
> lock(this)
> {
> Console.WriteLine("Client " + ID2HostName[clientID] + " ("+clientID+")
> disconnected!");
>
> ID2AliveStatus.Remove(clientID);
> ID2HostName.Remove(clientID);
>
> this.uniqueIDGenerator.ReleaseID(clientID);
> }
> }
>
> public string GetHostNameByClientID(int clientID)
> {
> lock(this)
> {
> return (string)ID2HostName[clientID];
> }
> }
>
> public void Ping(int clientID)
> {
> lock(this)
> {
> ID2AliveStatus[clientID] = true;
>
> Console.WriteLine("Pinged from " +
> ID2HostName[clientID]/*ID2HostName[clientID]*/ + " (" + clientID + ")");
> }
> }
>
> public ArrayList GetConnectedClientsList()
> {
> ArrayList list = new ArrayList();
> foreach(string hostName in ID2HostName.Values)
> {
> list.Add(hostName);
> }
>
> return list;
> }
>
> private void CheckForDeadClients(object state)
> {
> lock(this)
> {
> ArrayList keys = new ArrayList();
> foreach(int clientID in ID2AliveStatus.Keys)
> {
> keys.Add(clientID);
> }
>
> foreach(int clientID in keys)
> {
> if((bool)ID2AliveStatus[clientID])
> {
> ID2AliveStatus[clientID] = false; //sets alive status to false
> }
> else
> {
> TableLocks.GetProxy().ClientDied(clientID);
> ClientDisconnected(clientID);
> }
> }
> }
> }
>
> #region Remoting
> public static void RegisterServerObject()
> {
> RemotingConfiguration.RegisterWellKnownServiceType(
> typeof(ConnectedClientsManager),
> "ConnectedClientsManager",
> WellKnownObjectMode.Singleton );
> }
>
> private static ConnectedClientsManager proxy = null;
>
> public static ConnectedClientsManager GetProxy()
> {
> //%%%% uncommenting this line doesn't make difference!%%%%
> //lock(typeof(ConnectedClientsManager))
> {
> if(proxy == null)
> {
> proxy = (ConnectedClientsManager) Activator.GetObject(
> typeof(ConnectedClientsManager),
> "tcp://"+Global.ServerName+":45326/ConnectedClientsManager" );
> }
> }
>
> return proxy;
> }
> }
>
> //object never dies
> public override object InitializeLifetimeService()
> {
> return null;
> }
> #endregion
> }
>
>