Netchange

advertisement
Netchange
Concurrency Opgave 2, December 20161
Opdracht
Achtergrond
Het internet wordt gevormd door vele computers die met elkaar in verbinding staan en een groot
netwerk vormen. Op deze kaart kun je alle intercontinentale verbindingen zien. Niet tussen alle
landen is een directe verbinding, soms moeten IP-pakketjes via een aantal verschillende tussenstations hops maken om hun uiteindelijke bestemming te bereiken. Het is natuurlijk van groot belang
om de snelste route (minste aantal hops) te weten. Een extra uitdaging hierbij is dat verbindingen
soms kapot kunnen gaan. Het Netchange-algoritme kan in een netwerk van computers om de
verbindingen in kaart te brengen en zorgen dat in iedere computer bekend is welke computers allemaal bereikt kunnen worden en wat de kortste route is. Bovendien kan het Netchange-algoritme
dit adaptief: als verbindingen gemaakt of verbroken worden, wordt deze informatie door het hele
netwerk gepropageerd zodat iedereen een accuraat beeld heeft van welke computers te bereiken
zijn en via welke routes.
In deze opdracht implementeer je het Netchange-algoritme. We passen het Netchange-algoritme
niet toe op verschillende computers die via het internet verbonden zijn, maar op verschillende processen die allemaal op dezelfde computer draaien en communiceren via sockets. Door middel van
consolevensters kun je in deze processen verbindingen aanmaken en verbreken, en zien hoe het
netwerk in elkaar zit.
Netwerk
Een netwerk is te beschrijven als een verzameling V van processen. Een directe connectie tussen
twee buurprocessen u en v zorgt er voor dat u berichten aan v kan zenden, en vice versa. Als
u met v verbonden is en v met w, kan u naar w een bericht sturen door v als ‘tussenstation’ te
gebruiken. Om berichten naar andere processen te sturen, proberen we een pad van zo weinig
mogelijk stappen (hops) te vinden.
Zo kunnen we het netwerk modelleren als een graaf G = (V, A) waarbij elke pijl (u, v) in A een
directe verbinding is tussen u en v, en (u, v) is in A dan en slechts dan als (v, u) in A.
Een netwerk kan over de tijd veranderen:
• De directe verbinding (u, v) vervalt, bijvoorbeeld doordat de pijlen (u, v) en (v, u) verwijderd
worden uit A.
• Een nieuwe verbinding (u, v) wordt aangemaakt, doordat de pijlen (u, v) en (v, u) toegevoegd
worden aan A.
Door deze wijzigingen kan een proces u voor v het ene moment wel, en het andere moment niet
bereikbaar zijn.
Verschillende processen wisselen berichten met elkaar uit. Voor een effectieve en efficiënte
berichtwisseling moeten processen het kortste pad weten naar het andere proces in het netwerk.
Hiervoor houdt elk proces u een zogeheten routing table N bu bij. Voor elk proces v dient de
directe connectie (u, N bu (v)) de eerste buurman van u te zijn op het kortste pad van u naar v,
aangenomen dat er een pad bestaat. Hiernaast houdt elk proces u tevens de geschatte afstand
Du (v) bij naar elk proces v in V . Let op dat (u, N bu (v)) een bestaande uitgaande pijl van u is,
dus niet gelijk is aan (u, v) als die pijl niet bestaat.
Wanneer proces u een bericht b wil sturen aan proces v (met v ongelijk aan u), dan stuurt
hij bericht b aan zijn buurman y = N bu (v) over de directe verbinding (u, y). Zodra y bericht b
1 Versie:
22 november 2016.
1
ontvangt, ziet hij bestemming v. Indien y niet gelijk is aan v, stuurt y bericht b door naar N by (v).
Dit herhaalt zich totdat bericht b bij proces v is aangekomen. Uiteraard dienen routing tables
door het netwerk zelf opgebouwd en onderhouden te worden. Denk er hierbij aan dat het netwerk
kan veranderen terwijl processen nog bezig zijn met het bijwerken van hun routing tables.
In deze opdracht schrijf je een programma dat via het Netchange-algoritme een netwerk op kan
bouwen met andere instanties van dit programma. Door commando’s in de console in te geven
is het mogelijk om verbindingen met andere processen te maken of te verbreken. Verder is het
mogelijk om berichten naar andere processen te versturen.
Een beschrijving van het Netchange-algoritme kun je vinden in Netchange.pdf.
Sockets
Alle processen communiceren met elkaar met behulp van sockets. Hierdoor is het theoretisch
mogelijk om de processen op verschillende computers te laten draaien, maar voor het testen zullen
we altijd alle processen op één enkele computer te laten draaien. De connectie (u, v) en (v, u)
tussen buren u en v kunnen dezelfde socket gebruiken, dit is echter niet verplicht. Meer informatie
over socket- en serversocketgebruik kan je vinden in de API van C#. Een voorbeeld van een simpel
netwerk is te vinden op de website. Het voorbeeld moet nog wel aangepast worden voor gebruik
met meerdere clients.
Threads
Het programma dat je schrijft moet multithreaded zijn. Er moeten verschillende threads zijn voor:
• Interactie met de gebruiker via de console
• Het aannemen van inkomende nieuwe verbindingen
• Het ontvangen van berichten van bestaande buurprocessen
Er moet dus voor ieder buurprocess een thread zijn die de inkomende communicatie met dat
process afhandelt. De threads zullen gebruik maken van gedeelde resources (zoals de routing
table). Het is nodig om deze toegang te synchroniseren, hiervoor mag je de ingebouwde lockstatement van C# gebruiken. Een onderdeel van de beoordeling is dat de locking zo fijn mogelijk
is (niet de hele routing-tabel locken maar slechts een deel er van) - maar het belangrijkste is dat
je programma goed werkt.
Deel 1: Opzetten netwerk
Elke instantie van de applicatie is een proces. De processen in het netwerk zullen met elkaar
communiceren door middel van sockets. De parameters, die het programma bij het opstarten
meekrijgt, geven zijn eigen poortnummer aan en de poortnummers van de buren waarmee het
proces een directe verbinding heeft.
Alle processen in het netwerk voeren exact hetzelfde programma uit dat opgestart wordt via
de command prompt, en de processen verschillen alleen van elkaar door middel van meegegeven
parameters.
Initiatie netwerk
In de volgende voorbeelden nemen we aan dat je executable NetwProg heet. Bij het opstarten
wordt door middel van een aantal command-line arguments aangegeven (1) op welk poortnummer
het programma verbinding moet maken en (2) met welke andere poortnummers het programma
bij het opstarten een netwerk moet opbouwen. De syntax ziet er zo uit:
NetwProg ep bm1 bm2 ...
2
De parameters hebben de volgende betekenis:
• ep: ep is het unieke eigen poortnummer, dat andere processen meekrijgen om verbinding
te maken met dit proces. Poortnummers zijn een (geheel) getal van 1-65535, wij zullen
veelgebruikte poortnummers vermijden om conflicten met andere applicaties te voorkomen.
• bmi : Een buurpoortnummer bmi geeft aan dat bij het opstarten van het huidige process,
verbinding moet worden gemaakt met het process op poort bmi . Dit wordt altijd symmetrisch
gedaan, dat wil zeggen dat als bmi voorkomt in de command-line arguments van het process
met poort ep, dan staat ep in de lijst van buurpoorten van het process op poort bmi .
Een enkele node zonder neighbours is ook een netwerk (de lijst met bmi ’s kan dus leeg zijn), en
je programma moet de mogelijkheid hebben om twee verschillende netwerken (uiteraard alleen
bestaande uit jouw eigen versie van NetwProg) aan elkaar te koppelen. Hierbij mag je er van
uitgaan dat een poortnummer uniek is, en dus niet in de beide netwerken voor zal komen. We
zullen nooit een process met zichzelf laten verbinden.
Voorbeeld
Om makkelijk meerdere processen op te kunnen starten, kun je gebruik maken van het DOScommando start. Een voorbeeld hiervan vind je in Standard.bat, hieronder weergegeven.
graaf.jpg geeft een grafische representatie van dit netwerk.
start
start
start
start
start
start
NetwProg
NetwProg
NetwProg
NetwProg
NetwProg
NetwProg
1100
1101
1102
1104
1105
1106
1102
1100
1100
1102
1104
1105
1101
1102
1101
1105
1106
1102
1106
1104
Deel 2: Invoer
Elk proces moet in zijn eigen console draaien om te communiceren met de gebruiker, waarbij
Console.Title gelijk moet zijn aan “NetChange poortnummer”. Door middel van de console
moet de gebruiker de mogelijkheid hebben om de volgende commando’s in te voeren. In het
volgende noemen we het poortnummer van het huidige process u.
• Toon routing table - R: Laat direct de huidige routing table N bu (v) zien. Hierin staan
alle processen (poortnummers) die vanuit het proces bereikbaar zijn, de (bekende) kortste
afstand tot die processen en de buurnode via welke deze kortste afstand te bereiken is allemaal gescheiden door spaties.
1100
1101
1102
1103
0
1
1
2
local
1101
1102
1101
• Stuur bericht - B poortnummer string: verstuurt string naar poortnummer waarna
poortnummer dit naar de console print. Deze string kan spaties bevatten en krijgt niet
per definitie aanhalingstekens mee om het begin en einde mee aan te geven. Bij een bericht
naar een onbekend poortnummer wordt een foutmelding geprint.
• Maak verbinding - C poortnummer: maakt poortnummer een directe buurman van u.
Het C-commando wordt maar op 1 van de consoles gegeven, als u het commando C v krijgt
dan krijgt v niet ook het commando C u.
3
• Verbreek verbinding - D poortnummer: verbreekt de verbinding tussen u en poortnummer.
Net als C wordt dit commando maar op één van de twee processen gegeven. Let op dat hier
een netwerkpartitie bij kan ontstaan. Bij een poortnummer waar geen directe verbinding
mee is wordt een foutmelding geprint.
De commando’s staan hier in de volgorde (waarvan wij denken) dat ze het best te implementeren zijn.
Deel 3: Uitvoer
Om het automatisch testen met TomJudge mogelijk te maken, is het belangrijk dat je de uitvoerspecificatie precies volgt. Bij de volgende gebeurtenissen moet een bericht naar de console worden
geschreven:
• Als de afstandsschatting van een process wordt bijgewerkt:
Afstand naar v is nu d via h
• Bij het ontstaan van een directe verbinding met het process op poort p:
Verbonden: p
• Bij het verbreken van een directe verbinding met het process op poort p:
Verbroken: p
• Als het process op poort p door een netwerkpartitie onbereikbaar is geworden:
Onbereikbaar: p
• Indien bij een B- of D-commando een ongeldig poortnummer p wordt opgegeven:
Poort p is niet bekend
• Als een bericht wordt doorgestuurd:
Bericht voor v doorgestuurd naar h
• Als een bericht voor het process zelf wordt ontvangen toon dit bericht dan verbatim op de
console.
• Als je extra debug-informatie wil printen laat dit dan voorgaan door //:
//Deze regel wordt door TomJudge genegeerd, lucht hier gerust je hart!
Beoordeling
Net als bij het eerste prakticum is er weer een testprogramma beschikbaar, TomJudge2.exe. Wij
gebruiken dit programma ook bij de beoordeling, dus het is heel verstandig om zelf je programma
door TomJudge2 te laten checken.
Zet het bestand TomJudge2.exe in dezelfde map als de *.cs-bestanden van je project. TomJudge2 zoekt vervolgens automatisch in de ./bin/debug-map naar de debug-versie van je executable. Het is belangrijk dat je voordat je test met TomJudge2 eerst zorgt dat de debug-versie
van je project up-to-date is (gebruik F5 of F6 in Visual Studio). Je kunt eventueel ook de locatie van je executable doorgeven als argument, voer dan in de opdrachtprompt in: TomJudge2
"C:/Concurrency/Programma.exe".
Als je vervolgens op de knop om te testen drukt worden de tests gedraaid, dit kan enkele
minuten duren. Voor de tests worden poorten uit het bereik 55500-55519 gebruikt. Als het goed
is wordt alles groen, als het (nog) niet goed is worden sommige dingen rood. Klik eventueel op de
testcase voor meer details en hints en probeer het te verbeteren. Een programma dat alle testcases
correct heeft, scoort waarschijnlijk een zeer hoog cijfer. Een aantal mogelijke uitzonderingen hierop
is:
4
• Je programma mag geen code bevatten die specifiek is aan de gebruikte testcases.
• Er moet aan de implementatie-eisen in de opdracht (zoals het gebruik van threads voor het
afhandelen van connecties en sockets) voldaan zijn.
• Fraude of plagiaat.
TomJudge kan enkele criteria van het programma niet beoordelen. Naast correcte werking in
TomJudge kijken we onder andere ook nog naar of je programma selectief is in de locking.
Let op: Verkeerde NetChange-programma’s zijn soms niet-deterministisch: afhankelijk van
hoeveel geluk je hebt gaat een testcase soms wel/niet goed. De tests in TomJudge2 worden
standaard 3x herhaald, maar we raden aan om de tests nog een aantal keer opnieuw te draaien
om zeker te weten dat alles goed werkt (dit doen wij bij het nakijken namelijk ook!).
NB: TomJudge2 werkt alleen op Windows. Het daarom is niet verplicht om TomJudge2 te
gebruiken maar voor het nakijken is het handig als je het bestand report.csv dat TomJudge2
aanmaakt ook inlevert. Let er ook op dat TomJudge2 op verschillende computers andere beoordeingen kan geven, het is voor ons immers niet te doen om het op al jullie computers uit te proberen.
TomJudge2 geeft alleen een indicatie en is bedoeld om te helpen, maar we gaan bij het nakijken
er van uit hoe je programma op onze computer wordt beoordeeld.
Hints&Tips
Nog een aantal extra aanwijzingen en belangrijke tips:
• Het afhandelen van inkomende connecties dient in aparte threads te gebeuren. Elk proces
heeft daarom voor elke buurman een aparte thread die inkomende berichten afhandelt. Je
mag niet de berichten op een centrale queue plaatsen en die één voor één afhandelen.
• Vergeet niet om toegang tot gedeelde data (met name: routing table) op de juiste manier te
synchroniseren. Je mag voor deze opdracht gebruik maken van de ingebouwde locks in C#,
maar niet van objecten uit bijvoorbeeld de System.Collections.Concurrent namespace. Als
je zulk soort objecten wilt gebruiken moet je die zelf bouwen.
• Het is mogelijk dat een proces probeert te verbinden met een proces dat nog niet opgestart
is. In dat geval moet je de opgeleverde exception afvangen, een aantal miliseconden slapen,
en nog een keer proberen.
• Onnodig gebruik van spinlocks wordt zwaar gestraft in het cijfer. Een netwerk dat opgestart
is zou, indien idle, een zeer klein percentage van de CPU moeten gebruiken. Programma’s
die +/- 100% CPU gebruiken in idle stand kunnen en zullen niet nagekeken worden. Als je
programma zoveel CPU gebruikt dat het testen in TomJudge je computer doet vastlopen,
kunnen wij er geen cijfer aan geven.
• Bij het verbreken van verbindingen kan er een netwerkpartitie onstaan. Hierdoor komt het
Netchange-algoritme in een oneindige loop waarbij de afstandschatting steeds omhoog gaat.
Dit moet je afvangen zodat de loop stopt. (Hint: je programma hoeft een netwerk met
maximaal 20 clients aan te kunnen. Het kan ook nog slimmer!)
5
Download