Modified clock synchronization approach slightly so that we allow 5

seconds to pass in between ping/pong latency samples. Additionally, we
resync the clock every 10 minutes.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2748 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2003-08-08 20:20:39 +00:00
parent 3034364579
commit 732c0aab41
2 changed files with 81 additions and 71 deletions
@@ -1,5 +1,5 @@
//
// $Id: Client.java,v 1.39 2003/07/17 21:39:15 mdb Exp $
// $Id: Client.java,v 1.40 2003/08/08 20:20:39 mdb Exp $
package com.threerings.presents.client;
@@ -8,6 +8,8 @@ import java.util.List;
import com.samskivert.util.ObserverList;
import com.samskivert.util.ResultListener;
import com.samskivert.util.Interval;
import com.samskivert.util.IntervalManager;
import com.threerings.presents.Log;
import com.threerings.presents.data.ClientObject;
@@ -322,6 +324,18 @@ public class Client
// this will initiate the logon process
_comm = new Communicator(this);
_comm.logon();
// register an interval that we'll use to keep the clock synced
// and to send pings when appropriate
_piid = IntervalManager.register(new Interval() {
public void intervalExpired (int id, Object arg) {
if (id != _piid) {
IntervalManager.remove(id);
} else {
tick();
}
}
}, 5000L, null, true);
}
/**
@@ -351,6 +365,9 @@ public class Client
return false;
}
// kill our tick interval
_piid = -1;
// ask the communicator to send a logoff message and disconnect
// from the server
_comm.logoff();
@@ -358,34 +375,46 @@ public class Client
return true;
}
/**
* Called every five seconds; ensures that we ping the server if we
* haven't communicated in a long while and periodically resyncs the
* client and server clock deltas.
*/
protected void tick ()
{
long now = System.currentTimeMillis();
if (_dcalc != null) {
// if we're syncing the clock, send another ping
PingRequest req = new PingRequest();
_comm.postMessage(req);
_dcalc.sentPing(req);
} else if (now - _comm.getLastWrite() > PingRequest.PING_INTERVAL) {
// if we haven't sent anything over the network in a while, we
// ping the server to let it know that we're still alive
_comm.postMessage(new PingRequest());
} else if (now - _lastSync > CLOCK_SYNC_INTERVAL) {
// resync our clock with the server
establishClockDelta(now);
}
}
/**
* Called during initialization to initiate a sequence of ping/pong
* messages which will be used to determine (with "good enough"
* accuracy) the difference between the client clock and the server
* clock so that we can later interpret server timestamps.
*/
protected void establishClockDelta ()
protected void establishClockDelta (long now)
{
// create a new delta calculator and start the process
_dcalc = new DeltaCalculator();
PingRequest req = new PingRequest();
_comm.postMessage(req);
_dcalc.sentPing(req);
}
/**
* This is called when we've completed the process of pinging the
* server a few times to establish our clock delta.
*/
protected void clockDeltaEstablished ()
{
// initialize our invocation director
_invdir.init(_comm.getDObjectManager(), _cloid, this);
// we can't quite call initialization completed at this point
// because we need for the invocation director to fully initialize
// (which requires a round trip to the server) before turning the
// client loose to do things like request invocation services
_lastSync = now;
}
/**
@@ -484,9 +513,17 @@ public class Client
// extract bootstrap information
_cloid = data.clientOid;
// initialize our invocation director
_invdir.init(_comm.getDObjectManager(), _cloid, this);
// send a few pings to the server to establish the clock offset
// between this client and server standard time
establishClockDelta();
establishClockDelta(System.currentTimeMillis());
// we can't quite call initialization completed at this point
// because we need for the invocation director to fully initialize
// (which requires a round trip to the server) before turning the
// client loose to do things like request invocation services
}
/**
@@ -502,21 +539,15 @@ public class Client
return;
}
if (_dcalc.gotPong(pong)) {
// we're either done with our calculations, so we can grab the
// time delta and finish our business...
_serverDelta = _dcalc.getTimeDelta();
// free up our delta calculator
_dcalc = null;
// let the client continue with its initialization
clockDeltaEstablished();
Log.info("Time offset from server: " + _serverDelta + "ms.");
// we update the delta after every receipt so as to immediately
// obtain an estimate of the clock delta and then refine it as
// more packets come in
boolean done = _dcalc.gotPong(pong);
_serverDelta = _dcalc.getTimeDelta();
} else {
// ...or we'll either be sending another ping
PingRequest req = new PingRequest();
_comm.postMessage(req);
_dcalc.sentPing(req);
if (done) {
Log.info("Time offset from server: " + _serverDelta + "ms.");
_dcalc = null;
}
}
@@ -637,6 +668,15 @@ public class Client
* server. */
protected DeltaCalculator _dcalc;
/** The last time at which we synced our clock with the server. */
protected long _lastSync;
/** Our tick interval id. */
protected int _piid = -1;
/** How often we recompute our time offset from the server. */
protected static final long CLOCK_SYNC_INTERVAL = 600 * 1000L;
// client observer codes
static final int CLIENT_DID_LOGON = 0;
static final int CLIENT_FAILED_TO_LOGON = 1;
@@ -1,5 +1,5 @@
//
// $Id: Communicator.java,v 1.32 2003/07/17 21:39:15 mdb Exp $
// $Id: Communicator.java,v 1.33 2003/08/08 20:20:39 mdb Exp $
package com.threerings.presents.client;
@@ -13,8 +13,6 @@ import java.net.InetAddress;
import java.net.InetSocketAddress;
import com.samskivert.io.NestableIOException;
import com.samskivert.util.Interval;
import com.samskivert.util.IntervalManager;
import com.samskivert.util.LoopingThread;
import com.samskivert.util.Queue;
import com.samskivert.util.RuntimeAdjust;
@@ -96,15 +94,6 @@ public class Communicator
// start up the writer thread if everything went successfully
_reader = new Reader();
_reader.start();
// register an interval to send pings when appropriate
_piid = IntervalManager.register(new Interval() {
public void intervalExpired (int id, Object arg) {
if (checkNeedsPing()) {
postMessage(new PingRequest());
}
}
}, 5000L, null, true);
}
/**
@@ -120,8 +109,6 @@ public class Communicator
return;
}
stopPingInterval();
// post a logoff message
postMessage(new LogoffRequest());
@@ -236,9 +223,6 @@ public class Communicator
// clear out our reader reference
_reader = null;
// in case we haven't already done it.
stopPingInterval();
if (_writer == null) {
// there's no writer during authentication, so we may be
// responsible for closing the socket channel
@@ -331,6 +315,14 @@ public class Communicator
updateWriteStamp();
}
/**
* Returns the time at which we last sent a packet to the server.
*/
protected synchronized long getLastWrite ()
{
return _lastWrite;
}
/**
* Makes a note of the time at which we last communicated with the
* server.
@@ -340,27 +332,6 @@ public class Communicator
_lastWrite = System.currentTimeMillis();
}
/**
* Checks to see if we need to send a ping to the server because we
* haven't communicated in sufficiently long.
*/
protected synchronized boolean checkNeedsPing ()
{
long now = System.currentTimeMillis();
return (now - _lastWrite > PingRequest.PING_INTERVAL);
}
/**
* Stops our ping interval.
*/
protected void stopPingInterval ()
{
if (_piid != -1) {
IntervalManager.remove(_piid);
_piid = -1;
}
}
/**
* Reads a new message from the socket (blocking until a message has
* arrived).
@@ -600,7 +571,6 @@ public class Communicator
protected SocketChannel _channel;
protected Queue _msgq = new Queue();
protected int _piid = -1;
protected long _lastWrite;
/** We use this to frame our upstream messages. */