03 March, 2012

Get Servertime per Java

Eine Cousine kam mit einem Problem zu mir: Sie studiert auf einer sehr gut besuchten Uni.
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