Bei einer Vorlesungsanmeldung waren z.B. 240 Plätze innerhalb von 4 Sekunden weg.
Lösung: Automatisierte Anmeldung.
Nach einigen Tests war klar, es kann klappen. Sie arbeitete bis dahin mit einer online-AtomUhr um die exakte Uhrzeit fürs Anmelden zu erwischen.
Wer allerdings mit der Server-Client Architektur bzw. Webservices vertraut ist, weiss, dass es eigentlich nur um die Uhrzeit am Server geht.
Dafür habe ich einen kleinen Algorithmus versucht zu entwickeln welcher die Uhrzeit vom Server auf ca. 50ms genau bestimmen kann.
public long getServerTime() throws Exception
{
int accuraty = 250;
long startt = System.currentTimeMillis();
//url des Servers
URL reference = getTimeRefURL(); //URL to Target Server
HttpURLConnection givemetime;
//WarmUp
givemetime = (HttpURLConnection) reference.openConnection();
givemetime.setRequestMethod("HEAD");
givemetime.connect();
long stt;
long serverdate;
long cur_del;
long startoffset = 0;
long now_off = 0;
//upper boundary
long conn_delay = 0;
int step = accuraty;
int start_ms = 0;
int direction = 1;
int i;
long changes=0;
int founds = 0;
boolean found_change = false;
int fail = 0;
for(i=0; i < 1000/accuraty+2; i++)
{
if(fail >=5)
break;
if(i== 1000/accuraty && !found_change)
break;
start_ms = 1000 + start_ms;
start_ms = start_ms%1000;
givemetime = (HttpURLConnection) reference.openConnection();
givemetime.setRequestMethod("HEAD");
givemetime.setReadTimeout(1000);
while((stt = System.currentTimeMillis())%1000 != start_ms)
{} //wait for the perfect moment
serverdate = givemetime.getDate();
cur_del = System.currentTimeMillis()- stt;
if(cur_del > 1300)
{
fail ++;
i--;
continue;
}
long checked_at = (stt+cur_del/2);
conn_delay +=cur_del;
//first_run
if(i==0)
startoffset = (serverdate - (checked_at-checked_at%1000))/1000;
now_off = (serverdate - (checked_at-checked_at%1000))/1000;
if(now_off == startoffset)
{
start_ms += step*direction;
continue;
}
found_change = true;
changes += checked_at%1000;
founds ++;
if(now_off > startoffset)
direction = -1;
else
direction = 1;
startoffset = now_off;
step = step/2;
start_ms += step*direction;;
}
if(fail >= 5)
throw new TimeoutException();
long offset;
if(founds > 0)
{
if(direction == -1)
now_off-=1;
offset = now_off*1000 + (1000-changes/founds);
}else
offset = startoffset*1000;
System.out.println("offs:"+offset*-1+" average_delay:"+(conn_delay/(i)));
System.out.println("needed: "+(System.currentTimeMillis()-startt));
return offset*-1;
}
Is ein langer, schircher Code, schon klar, aber hey, es funktioniert! (fast immer)Also, im Prinzip wird im Response vom Server nach der Umschaltung zwischen 2 Sekunden gesucht. Ist eine Umschaltung geschehen, wird der Step von z.B. 250ms auf 125ms reduziert und in die andere Richtung gegangen, um wieder einen Step zu finden.
Haben wir eine Umschaltung genau gefunden, wissen wir z.B. dass, wenn wir auf 500ms stehen, der Server umschaltet --> delay von 500ms
Der Delay eines Requests wird immer halbiert um zu bestimmen, auf wann diese Zeit bezogen werden kann.
Im Endeffekt liefert der Code die Millisekunden zurück, oder eine TimeOut-Exception, sollten die Request zu lange brauchen (zu ungenau).
Nachteil: Der Code braucht lange. Je nach Steps zwischen 6-10 Sekunden.
Vorteil: Wenn Steps gefunden werden, ziemlich genau.
Bitte natürlich um Verbesserungen/Vorschläge etc. ;)
No comments:
Post a Comment