sammenligning af tidspunkter - datetime - problematik
Jeg har lavet et lille server - klient program - Bruuns Auktionshus. En klient kan via en GUI indtaste et bud. Samtidigt generes der et budtidspunkt som sendes til serveren. Det virker fint. Men når budtidspunktet skal sammenlignes med et tidstempel genereret med et sekunds mellemrum, sat af serveren inde i den anden while lykke i min HaandterKunde() metode sker der ligesom ikke noget. Det er meningen at hvis en kunde byder inden der er gået 10 sekunder skriver serveren "ingen højere" og det skal så være muligt for en ny kunde at byde. Det skal så være den nye tid der sammenlignes. Så langt så godt. Men hvis der er gået 10 sekunder uden der på ny er budt, skal serveren skrive til kunden/erne beskeden "første". Hvis der er gået yderligere 5 sekunder skal der skrives "anden" og hvis der er gået yderligere 3 sekunder skal der skrives "tredie, varen er solgt!". Men det gør den ikke. Det er ligesom sammenligningen aldrig bliver foretaget, kommer ikke ind i if-sætningerne i den anden while lykke.
Autionshusvarer er et singleton objekt.
Er der nogen der kan fortælle mig hvad jeg gør galt?
public void HaandterKunde() { double budFraKunde; string serverBesked; DateTime budTidspunkt;
NetworkStream networkStream = new NetworkStream(this.kunde); StreamReader streamReader = new StreamReader(networkStream); StreamWriter streamWriter = new StreamWriter(networkStream);
while(true) //sålænge der kommunikeres med kunde { try { //server læser bud og budtidspunkt fra kunde budFraKunde = Convert.ToDouble(streamReader.ReadLine()); budTidspunkt = Convert.ToDateTime(streamReader.ReadLine());
//sammenlign bud fra kunde med varen på auktions aktuelle hoejeste bud
if(budFraKunde <= Auktionsvarer.GetAuktionsvarer().VarePaaAuktion().GetHoejesteBud()) { //broadcast serverbesked til de andre kunder serverBesked = "Budet på "+budFraKunde+" kr. er for lavt! "+budTidspunkt+" Giv nyt bud";
//budet skal kun sættes hvis det er højere end startbudet, så det gælder som den nye mindstepris Auktionsvarer.GetAuktionsvarer().VarePaaAuktion().SetHoejesteBud(budFraKunde); Auktionsvarer.GetAuktionsvarer().VarePaaAuktion().SetBudTidspunkt(budTidspunkt);
//her er mit problem, den kommer ligesom aldrig ind og foretager sammenligningen //så er der gået 10 sekunder uden nogen har budt if(budTidspunkt.Equals(tidstempel)) { hammerslag = "første"; monitor.BroadcastServerBeskedTilKunde(kundeIPadresse, hammerslag); }
TimeSpan attenSekunder = new TimeSpan(0,0,18); tidstempel = tidstempel.Subtract(attenSekunder); if(budTidspunkt == tidstempel) { hammerslag = "tredie, varen er solgt!"; monitor.BroadcastServerBeskedTilKunde(kundeIPadresse, hammerslag); int vareNr = Auktionsvarer.GetAuktionsvarer().VarePaaAuktion().GetVareNr(); Auktionsvarer.GetAuktionsvarer().RemoveEnVare(vareNr); break; }
//give mulighed for at ny kunde kan give et bud budFraKunde = Convert.ToDouble(streamReader.ReadLine()); budTidspunkt = Convert.ToDateTime(streamReader.ReadLine());
counter++; }//end indre while løkke (hammerslag)}//end ydre while løkke
}//end ydre while løkke
//fjern streamwriter fra monitor monitor.RemoveStreamWriter(streamWriter);
Console.WriteLine("Forbindelse til kunde lukkes ned...\n"); streamWriter.Close(); streamReader.Close(); networkStream.Close(); }
// INDSÆT DENNE LINIE Console.WriteLine("her1 budTidspunkt = "+budTidspunkt+", tidstempel = "+tidstempel); //her er mit problem, den kommer ligesom aldrig ind og foretager sammenligningen //så er der gået 10 sekunder uden nogen har budt if(budTidspunkt.Equals(tidstempel)) { Console.WriteLine("her2"); hammerslag = "første"; monitor.BroadcastServerBeskedTilKunde(kundeIPadresse, hammerslag); } Console.WriteLine("her3");
bruge visual studios "output" vindue til at se hvad der præcis sker... der er vel 2 muligeder : 1) fejlen ligger i koden ovenover (måske hænger den eller exit i koden - exceptions!?) 2) fejlen ligger i sammenligningen: if(budTidspunkt.Equals(tidstempel))
hov?! det ser lidt mystisk ud... din sammen ligning er noget med "equals" eller "=" hvilket betyder at dine tidspunkter skal være HELT præcis ens (ned til millisekunder) - vil dette være tilfældet?
...ved ikke lige hvordan din kode hænger sammen, men jeg kunne forestille mig at at du skulle lave noget med <= eller >= i din sammenligning for at undgå at de skal matche værdien på millisekundspræcis. :o ?!?!?
Du aflæser et tidspunkt som sendes til server fra klienten. Med den metode er du afhængig af af klienternes og serverens ure går ens. Dette er en meget risikabel antagelse - i stedet bør du udelukkende arbejde med server-tid.
hej sovsekoder og nielle tak for jeres hjælp. Nu har jeg lavet budtidspunktet om til en servertid. denne tid sættes på varen. jeg forestiller mig at den så står stille. Inde i den anden while løkke sættes et andet tistempel der skal bruges til sammenligning. Dette tidstempel forestiller jeg mig genereres med et sekunds mellemrum. Det jeg gerne vil kode er: if(budTidspunkt > tidstempel - 10 sekunder) f.eks. hvis budTidspunktet er 10.16.32 > 10.16.40 - 10 sekunder) så er tidspunkterne ikke ens og der er ikke gået 10. dvs. en ny klient kan have budt og det er hans tid der bruges indtil en ny klient byder osv. Det er først når tidstemple er nået op på 10.16.32 == 10.16.42 - 10 sekunder at tiderne er ens, dvs. der er gået 10 sekunder uden nogen har budt også er det den skal skrive "første" men det gør den ikke. Men det kan godt være det ikke udtrykkes rigtigt med tidstempel = tidstempel.subtract(tiSekunder). tidstemplet skal vokse med et sekund hele tiden og budtidspunktet skal stå stille. Jeg har prøvet at debugge og sætte console.Writeline() ind, men den kommer bare ikke ind i if-sætningen. Jeg håber ikke jeg lyder alt for tosset men jeg er lidt ny mht. til at kode.
Nej, du skal ikke lægge den som et svar. Eksperten bruger "svar" til at kunne give point til dem som spørgeren synes skal have point. Det bruges ikke til når man svare på hinandens spørgsmål. :^)
Prøv at vise os den seneste version af koden - den er vel lavet en del om nu i forhold til det ovenstående.
Nu ser koden sådan her ud. Efter at jeg sammenligner tiderne på seconds kunne jeg godt bruge equals eller ==. Det virkede også da jeg kun kørte en kunde igennem. Men når jeg giver mulighed for at køre flere kunder igennem, det kan jeg kun hvis jeg gentager indlæsning af budFraKunde og budTidspunkt inde i den 2'den while løkke så opfører den sig ikke helt efter reglerne. Den springer f.eks. beskeden "første" over og uret går ikke på serveren hvis jeg ikke har givet bud fra 2 til 3 kunder. Uret skulle jo gerne starte med den første kunde der giver et bud. Men den står bare og bliker på consollen. Jeg ved ikke rigtig hvad jeg gør galt???
//trådmetode som modtager bud fra en klient og sender budet videre til alle de //andre kunder
public void HaandterKunde() { double budFraKunde; string serverBesked; DateTime budTidspunkt;
NetworkStream networkStream = new NetworkStream(this.kunde); StreamReader streamReader = new StreamReader(networkStream); StreamWriter streamWriter = new StreamWriter(networkStream);
//tilfoej streamwriter til monitor monitor.AddStreamWriter(streamWriter);
//send velkomst til kunde serverBesked = "\rVelkommen til Bruuns Auktionshus! \rVare på auktion er: "+this.GetVare().ToString()+"\rGiv bud"; monitor.BroadcastServerBeskedTilKunde(kundeIPadresse, serverBesked);
while(true) //sålænge der kommunikeres med kunde { try { //server læser bud fra kunde budFraKunde = Convert.ToDouble(streamReader.ReadLine()); budTidspunkt = DateTime.Now; //budtidspunkt er nu sat på serversiden monitor.BroadcastAuktionsBud(kundeIPadresse, budFraKunde, budTidspunkt); } catch(IOException) { break; }
//sammenlign bud fra kunde med varen på auktions aktuelle hoejeste bud if(budFraKunde <= Auktionsvarer.GetAuktionsvarer().VarePaaAuktion().GetHoejesteBud()) { //broadcast serverbesked til de andre kunder serverBesked = "Budet på "+budFraKunde+" kr. er for lavt! "+budTidspunkt+" Giv nyt bud"; monitor.BroadcastServerBeskedTilKunde(kundeIPadresse, serverBesked); continue; }
//budet skal kun sættes hvis det er højere end startbudet, så det gælder som den nye mindstepris Auktionsvarer.GetAuktionsvarer().VarePaaAuktion().SetHoejesteBud(budFraKunde); Auktionsvarer.GetAuktionsvarer().VarePaaAuktion().SetBudTidspunkt(budTidspunkt);
//problem her //give mulighed for at ny kunde kan give et bud budFraKunde = Convert.ToDouble(streamReader.ReadLine()); budTidspunkt = Auktionsvarer.GetAuktionsvarer().VarePaaAuktion().GetBudTidspunkt();
//udskrive det nye bud monitor.BroadcastAuktionsBud(kundeIPadresse, budFraKunde, budTidspunkt); continue; }
//så er der gået 10 sekunder uden nogen har budt if(budTidspunkt.Second == tidstempel.Second) { Console.WriteLine("tidstempel 1 "+ tidstempel); hammerslag = "første"; Console.WriteLine("første"); monitor.BroadcastServerBeskedTilKunde(kundeIPadresse, hammerslag); continue; }
//fjern streamwriter fra monitor monitor.RemoveStreamWriter(streamWriter); Console.WriteLine("Forbindelse til kunde lukkes ned...\n"); streamWriter.Close(); streamReader.Close(); networkStream.Close(); }
Nu har jeg flyttet indlæsningen fra den første if-sætning til slutningen af løkken.
//give mulighed for at ny kunde kan give et bud budFraKunde = Convert.ToDouble(streamReader.ReadLine()); budTidspunkt = Auktionsvarer.GetAuktionsvarer().VarePaaAuktion().GetBudTidspunkt();
//udskrive det nye bud monitor.BroadcastAuktionsBud(kundeIPadresse, budFraKunde, budTidspunkt);
Nu skriver den "første" men ikke "anden" og "tredie, varen er solgt", tæller op en gang og står så og blinker. Jeg ved ikke hvorfor den ikke fortsætter med at tælle op så den kan foretage de andre sammenligninger, som den gør hvis jeg ikke gentager indlæsningen???
TimeSpan attenSekunder = new TimeSpan(0,0,18); tidstempel = tidstempel.Subtract(attenSekunder); if( budTidspunkt.Second == tidstempel.Second) { Console.WriteLine("tidstempel 3 "+tidstempel); Console.WriteLine("tredie, varen er solgt!"); hammerslag = "tredie, varen er solgt!"; monitor.BroadcastServerBeskedTilKunde(kundeIPadresse, hammerslag); break; }
//flyttet //give mulighed for at ny kunde kan give et bud budFraKunde = Convert.ToDouble(streamReader.ReadLine()); budTidspunkt = Auktionsvarer.GetAuktionsvarer().VarePaaAuktion().GetBudTidspunkt();
//udskrive det nye bud monitor.BroadcastAuktionsBud(kundeIPadresse, budFraKunde, budTidspunkt);
hej nielle det er virkelig morsomt. Hvis jeg skrev som du sagde if(buTidspunkt.AddSeconds(18) >= nu)osv, så skrev den varen er solgt med det samme, så når den slet ikke at tælle, og giver ikke mulighed for indtastning af nye bud. Så jeg vendte dem om, så der står if(buTidspunkt.AddSeconds(18) <= nu)osv Nu får jeg lov til at indtaste nye bud, men den skriver ingen højere 10 gange og første 5 gange og anden 3 gange før den tilsidst skriver tredie, varen er solgt og hopper ud af løkken. Og den løber hele baduljen igennem for hver nyt bud der bliver indtastet. Men det er det bedste resultat indtil videre, så nu stopper jeg for idag. Er træt. Men tusind tak for hjælpen. Jeg tror måske det ville være nemmere hvis man havde en timer, som genstartede med at tælle hver gang et nyt bud blev givet. Men jeg har slet ikke prøvet at arbejde med timere.
Hmm, jeg kan nu ikke se hvorfor at det skulle give et mere rigtigt resultat at vende >= til <=. Det er ikke en logisk opførelse (og det er også derfor at du får hammerslagene ud i den forkerte rækkefølge). Mht. det at hammerslagene bliver gentaget, så kan det klares med dette:
string hammerslag; int counter = 0; while (true) { Thread.Sleep(1000); DateTime nu = DateTime.Now;
Consol start budtidspunkt 14:06:19 start nu 14:06:19
budtidspunkt 3 14:06:19 nu 3 14:06:19 tredie, varen er solgt!
Der går 1 sekund, så skriver den tredie, varen er solgt! Dvs. nu når ikke at tælle op til 10, 15 eller atten, og skrive de korrekte beskeder til klienten. Inden jeg tilføjede hammerslag i if sætningerne havde jeg en else på den første if-sætning. Dvs. det der foregår i else er modsat det der foregår i if så hvis if(budTidspunkt.AddSeconds(18) >= nu, så må else være budTidspunkt.AddSeconds(18) < nu, og denne situation forekommer aldrig fordi budTidspunkt og nu har samme start værdi. hvorefter nu vokser med 1 for hvert sekund, Så derfor skriver den med det samme tredie, varen er solgt!. Den kommer aldrig ned i else sætningen og skriver beskeden "Ingen højere!". Sådan forstår jeg det ihvertfald, eller er jeg hel gal på den. Så prøvede jeg at vende tegnene om og nu har jeg tilføjet hammerslag til if-sætningerne for at fjerne gentagelser. Nedenfor ses resultatet jeg fik i min GUI med 2 indtastninger af bud på hhv. 6000 og 7000 med 3-4 sekunders mellemrum. Jeg kan godt se at denne løsning ikke er god, fordi varen sælges selvom der kommer et nyt bud, inden der er nået at gå 10 18 sekunder. Den løber hele den indre while løkke (hammerslag) igennem for hvert bud. Og det skal den jo ikke den skal stoppe, når der kommer et nyt bud også starte forfra med at tælle op til første, anden og tredie. Jeg håber dette bedre forklarer problemet. Det er en rigtig god øvelse vi har fået for man bliver tvunget til at tænke, men jeg synes den er svær.
GUI 127.0.0.1(1): Velkommen til Bruuns Auktionshus! Vare på auktion er:
Varenr.: 101 Betegnelse: Antikt skrivepult fra 1805 Hoejeste bud: 5000 Bud tidspunkt: 08-01-2006 14:37:26 Giv bud 127.0.0.1(1): 6000 08-01-2006 14:37:30 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): første! 127.0.0.1(1): 6000 08-01-2006 14:37:30 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): anden! 127.0.0.1(1): 6000 08-01-2006 14:37:30 127.0.0.1(1): første! 127.0.0.1(1): 6000 08-01-2006 14:37:30 127.0.0.1(1): anden! 127.0.0.1(1): 6000 08-01-2006 14:37:30 127.0.0.1(1): tredie, varen er solgt! 127.0.0.1(1): 7000 08-01-2006 14:37:49 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): første! 127.0.0.1(1): 7000 08-01-2006 14:37:49 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): Ingen højere? 127.0.0.1(1): anden! 127.0.0.1(1): 7000 08-01-2006 14:37:49 127.0.0.1(1): første! 127.0.0.1(1): 7000 08-01-2006 14:37:49 127.0.0.1(1): anden! 127.0.0.1(1): 7000 08-01-2006 14:37:49 127.0.0.1(1): tredie, varen er solgt!
int counter = 0; while(true) { DateTime nu = DateTime.Now; Thread.Sleep(1000);
Console.WriteLine("start Budtidspunkt "+budTidspunkt); Console.WriteLine("start nu "+nu);
// give mulighed for at ny kunde kan give et bud // budFraKunde = Convert.ToDouble(streamReader.ReadLine()); // budTidspunkt = Auktionsvarer.GetAuktionsvarer().VarePaaAuktion().GetBudTidspunkt();
// udskrive det nye bud monitor.BroadcastAuktionsBud(kundeIPadresse, budFraKunde, budTidspunkt); counter++;
Det du viser ner nu ikke 100% den kode som jeg har postet. I hvert fald er der en forskel hvor du har:
serverBesked = "Ingen højere?";
- mens jeg har:
hammerslag = "Ingen højere?";
Dette er grunden til at du har så mange linjer med "Ingen højere?" Jeg kan se mange flere afvigelser end det, så det er nu lidt misvisende når du skriver at du har "gjordt nøjagtig som du anviser". :^|
Nå, men videre til algoritmen...
Variablen budtidspunkt skulle gerne indeholde tidspunktet for det sidste bud - enten af den specifikke kunde eller af en af de andre som byder i samme auktion. Variaben nu skulle gerne indeholde ”klokken lige nu”.
1) Hvis ”nu” ligger 18 sekunder, eller mere, efter ”budtidspunkt” er hammerslaget lig ”tredie, varen er solgt!”. Dette skal skrives én gang.
Hvis 1) ikke er opfyldt, må ”nu” ligge mindre end 18 sekunder efter ”budtidspunkt”:
2) Hvis ”nu” ligger 15 sekunder, eller mere, efter ”budtidspunkt ” er hammerslaget ”anden”. Dette skal skrives én gang.
Hvis 2) heller ikke er opfyldt, må ”nu” ligge mindre end 15 sekunder efter ”budtidspunkt”:
3) Hvis ”nu” ligger 10 sekunder, eller mere, efter ”budtidspunkt ” er hammerslaget ”første”. Dette skal skrives én gang.
Hvis 3) heller ikke er opfyldt, må ”nu” ligge mindre end 10 sekunder efter ”budtidspunkt”:
4) Men så er hammerslaget ”Ingen højere?"”. Dette skal skrives én gang.
Dette er lige præcis det som denne algoritme burde gøre:
jeg sender dig de væsentligste kodebrokker fra mit program. Jeg har lavet en Bud klasse som har en pris og et budtidspunkt samt en auktionsbyder. Så har jeg lavet en Byd metode som sammenligner det indkomne bud med det højeste og returnerer en serverbesked til kunden. På denne måde får jeg sat mit bud og budtidspunkt på den aktuelle auktionsvare. Hvis det aktuelle højeste bud er mindre end det indkomne bud så sættes det nye bud som det højeste og beskeden "ingen højere" sendes til kunden. Og ellers får kunden besked på at indtaste et nyt bud, fordi det er for lavt. Derfor har jeg fjernet else if sætningen hvor if(Hammerslag Ingen højere) blev sammenlignet i den anden while løkke fra tidligere. Så det kun er hammerslag der sammenlignes. Og ellers bruger jeg din logaritme.
Det resultat jeg får er
127.0.0.1(1): Velkommen til Bruuns Auktionshus! Vare på auktion er:
Varenr.: 100 Betegnelse: Antik skrivepult fra 1805 Start pris: 5000 Giv bud 127.0.0.1(1): 6000 09-01-2006 18:39:48 127.0.0.1(1): Ingen højere! 127.0.0.1(1): tredie, varen er solgt!
på consollen står der startBudtidspunkt 18:39:48 start nu 18:39:48
budTidspunkt 3 18:40:06 //Men der er ikke gået 18 sekunder??? nu 3 18:39:48 tredie, varen er solgt!
skriver den ikke beskeden med det samme, fordi budTidspunktet er større end det første nu tidspunkt den sammenligner med? Den når ikke at tælle til hverken 18, 15, eller 10 og skrive de passende beskeder til kunden, førend den skriver "tredie, varen er solgt!" eller give mulighed for at indtaste et nyt bud. Hvad gør jeg forkert???
skal jeg ikke også på en eller anden måde bryde den anden while løkke, hvis et nyt bud gives?
public class Bud { private Auktionskunde auktionsbyder; //associering til auktionskunde objekt private double pris; private DateTime budTidspunkt;
//budTidspunktet sættes når der oprettes et bud this.budTidspunkt = budTidspunkt; }
//Get-metoder public DateTime GetBudTidspunkt(){return this.budTidspunkt;} public double GetPris(){return this.pris;} //Get-metode til associeret Auktionskunde objekt public Auktionskunde GetAuktionskunde(){return this.auktionsbyder;}
}//end class Bud
public class Auktionsvare { private int vareNr; //et unikt identifikationsnr. private string beskrivelse; //en beskrivelse af vare på auktion private double startPris; private Bud hoejesteBud; //ass. til Bud objekt - det aktuelle højeste bud for denne vare
public string Byd(Auktionskunde auktionsbyder, double budFraKunde, DateTime budTidspunkt) { string serverBesked = null; if(this.hoejesteBud == null || this.hoejesteBud.GetPris() < budFraKunde) { this.SetHoejesteBud(new Bud(auktionsbyder, budFraKunde, budTidspunkt)); serverBesked = "Ingen højere!"; } else //dvs. hvis hoejesteBud != null og hoejesteBud.GetPris() > budFraKunde { serverBesked = "Budet på "+budFraKunde+" kr. er for lavt! "+budTidspunkt+" Giv nyt bud\r\n"; serverBesked += "højesteBud er: "+this.hoejesteBud.GetPris()+" "+this.hoejesteBud.GetBudTidspunkt()+" "+auktionsbyder.GetNavn(); } return serverBesked; } }//end class Auktionsvare
public class AuktionshusServer { HaandterKunde() { //send velkomst til kunde serverBesked = "\rVelkommen til Bruuns Auktionshus! \rVare på auktion er: "+this.GetAuktionsvare().ToString()+"\rGiv bud";
while(true) //sålænge der kommunikeres med kunde { try { //server læser bud fra kunde budFraKunde = Convert.ToDouble(streamReader.ReadLine()); budTidspunkt = DateTime.Now; //budtidspunkt sat på serversiden
Auktionskunde byder = new Auktionskunde(kundeIPadresse); Auktionsvare varePaaAuktion = this.GetAuktionsvare();
//her sættes budet + tidspunkt og sammenligning med aktuelt højeste bud gøres
//sammenligning af budtidspunkt med servertid while(true) { DateTime nu = DateTime.Now; Thread.Sleep(1000); Console.WriteLine("start Budtidspunkt "+budTidspunkt); Console.WriteLine("start nu "+nu);
}//end indre while løkke (hammerslag) }//end ydre while løkke
}//end HaandterKunde }//end class Auktionshusserver
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.