Inhoudsopgave
Samenvatting
Dit is de opgave voor het examen van het vak ``Structuur van Computerprogramma's II'' voor de 2de zittijd van het academiejaar 2009-20010.
Het programma maakt gebruik van de normale internet protocollen en standaarden: TCP/IP, DNS. Zeer summier:
Een machine op het net heeft een numeriek
adres, meestal
voorgesteld als een rij van 4
bytes.
Bvb. is 134.184.65.2
het internet adres van tinf2
.
D.m.v. de DNS service kunnen een of meerdere namen
geassocieerd worden met een internet adres. Bvb.
is tinf2.vub.ac.be
de officiële naam
van de machine met adres 134.184.65.2
.
Zulke
namen zijn hiërarchisch gestructureerd (de machine
``tinf2
'' behoort
tot het domein ``vub.ac.be
'' dat zelf weer een
deeldomein is van ``ac.be
'', hetwelk een deel is van het ``top''
domein ``be
''.
Men kan bvb. d.m.v. het ``nslookup'' programma nagaan wat het adres
is dat hoort bij een naam (of omgekeerd).
Een machine op het net heeft een aantal
poorten waarlangs
een verbinding kan gemaakt worden met een poort van een andere machine.
Sommige poorten worden, bij conventie, gebruikt voor bepaalde diensten.
Bvb. wordt de poort nummer 80
veelal gebruikt door web servers.
Wanneer bvb. mozilla (of
konqueror, of netscape) vanop de machine
134.184.65.2
(tinf2
) een verbinding wenst te maken naar de webserver op
elvas.vub.ac.be
(adres 134.18.65.31
), dan wordt er
een verbinding geopend tussen een poort, bvb
8026
, op 134.184.65.2
en poort 80
op 134.18.65.31
.
D.m.v. het tcp protocol kunnen dan
data uitgewisseld worden tussen de toepassingen aan beide
kanten van de verbinding.
Voor het netwerk aspect kan gebruik gemaakt worden van
het
dvnet
pakket dat o.a. een klasse Socket
(voor clients) en
SocketServer
(voor servers) definieert.
Omdat Socket
afgeleid is van iostream
is het sturen en ontvangen van
gegevens via een netwerkverbinding heel makkelijk.
De map
client-server-demo
bevat een volledig uitgewerkt voorbeeld
van een ``echo server'', dit is een server die elke lijn gestuurd door
een client terugstuurt, na de tekst te hebben omgezet naar hoofdletters.
Omdat een typische server toepassing verschillende sessies/clients tegelijkertijd moet kunnen behandelen is het aangewezen om deze parallelle activiteiten te implementeren via verschillende ``threads'' [1].
Voor deze toepassing volstaat het een thread te beschouwen als een proces dat zijn address space deelt met een ander proces (dit is trouwens min of meer de huidige implementatie van threads in linux). De uitvoering van een thread wordt verder geregeld zoals voor een proces; een multi-threaded programma kan dus verschillende activiteiten gelijktijdig uitvoeren. Omdat threads dezelfde address space delen is er natuurlijk een probleem om gemeenschappelijke data structuren te beschermen tegen gelijktijdige toegang. Een simpele oplossing gebruikt daarvoor zgn. ``monitors'' , dat zijn stukken code die slechts door één thread tegelijk kunnen uitgevoerd worden.
Voor ``threads'' en ``monitors'' zijn klassen beschikbaar in de
dvthread
bibliotheek (Java ondersteunt gelijkaardige klassen). De
documentatie voor
dvthread
bevat ook een programma dat het gebruik van threads en
monitors illustreert om concurrente toegang tot een gedeelde buffer
te regelen voor verschillende ``reader'' en ``writer'' threads.
Indien een programma een onbekend aantal threads dient op te
starten is het nuttig om de nieuwe (sinds versie
0.4.5
) constructor functie van
Dv::Thread::Thread
te gebruiken: indien
met de constructor de bool parameter
true
wordt meegegeven, dan zorgt
de dvthread
bibliotheek ervoor dat het nieuw
aangemaakte Dv::Thread::Thread
object
automatisch wordt deleted wanneer de corresponderende thread
klaar is. Indien geen verdere informatie over de exit status
van een thread moet opgevraagd worden, dan spaart het gebruik van deze optie
een extra ``manager'' thread klasse uit die anders nodig zou
zijn om andere threads te vernietigen, eens ze klaar zijn.
In het onderstaand voorbeeld
wordt een klasse Session
afgeleid van
Dv::Thread::Thread
zodanig dat
elk Session
object op de hierboven beschreven manier vernietigd wordt.
Voorbeeld 1. Een thread klasse afgeleid van Dv::Thread::Thread
class Session: public Dv::Thread::Thread { public: /** Een Session kan alleen met deze "factory" functie gemaakt * worden. Op die manier wordt vermeden dat per abuus * een Session op de stack wordt gemaakt, wat desastreuze * gevolgen zou hebben. */ static Session* make(..) { return new Session(..); } /** Destructor. */ virtual ~Session(..) { .. } .. private: /** De echte constructor is private, zie hoger. * Het meegeven van de optionele parameter "true" aan de * Dv::Thread::Thread constructor zorgt ervoor dat het * dvthread pakket zelf een delete zal uitvoeren eens * de aangemaakte Thread klaar is. */ Session(..): Dv::Thread::Thread(true) { .. } .. };
Een typische server main loop ziet er dan uit zoals in de onderstaande code.
while (true) { .. // Accept a new connection. .. (Session::make(..))->start(); // Launch new session thread. .. }
E-mail berichten komen typisch aan op een server machine waar ze worden bewaard tot een gebruiker ze ophaalt. Dit laatste gebeurt dikwijls vanop een client machine waarop geen e-mail server beschikbaar is. Het ``post office protocol'' (POP) kan gebruikt worden om de conversatie tussen zo'n client en server machine te regelen.
Pop3 is een eenvoudig protocol dat een UA (user agent) programma toelaat om, vanop een client machine, e-mail berichten van een server af te halen en, in beperkte mate, te manipuleren (op de server). Het POP3 protocol is zeer eenvoudig en niet erg krachtig. Dikwijls zal daarom het IMAP protocol, dat meer mogelijkheden biedt om berichten op de server te behandelen, bvb. te filteren, gebruikt worden.
De specificatie van het POP3 protocol kan gevonden worden in het RFC (Request For Comments) document RFC1939.
Schrijf[2]
een POP3 server programma pop3d
dat de meest elementaire POP3 bevelen ondersteund, te weten:
USER
,
PASS
,
STAT
,
QUIT
,
RETR
,
DELE
,
LIST
,
NOOP
,
UIDL
,
TOP
.
Het starten van de server gebeurt d.m.v. het volgende bevel.
pop3d
configuration-file
waarbij de inhoud van het configuratiebestand een aantal parameters vastlegt, zoals getoond in het voorbeeld.
Voorbeeld 2. Voorbeeld pop3d configuratiebestand
# sample dvpop3d configuration file # port: portnumber on which server will be listening for connections port=9999 # top: top directory top=/home/dvermeir/pop3d/ # logfile: where log messages are written to logfile=dvpop3d.log # timeout is in seconds timeout=600
Een lijn in het configuratiebestand is dus ofwel een
commentaarlijn, die begint met het teken '#', ofwel
een definite van de vorm
naam=waarde
waarbij naam
en
waarde
één van de betekenissen
uit de onderstaande tabel hebben.
Tabel 1. Configuratie-elementen
Naam | Waarde |
---|---|
port | nummer van de poort gebruikt door de server |
logfile | name van het bestand voor logboodschappen |
top | name van de map waarin de usermappen staan |
timeout | aantal seconden dat de server wacht op client input, indien er gedurende
timeout seconden geen input was
moet de server de verbinding verbreken |
Opmerkingen:
top
als de naam
van een map waaronder zich weer gebruikersmappen bevinden,
één per gebruiker. Als
bvb top
verwijst naar
/home/fred/pop3
en lisa
is een gebruiker, dan zullen de berichten voor
lisa
zich bevinden in de map
/home/fred/pop3/lisa
. Een bericht
komt overigens overeen met een file. Een tar
bestand met een aantal berichten die als test kunnen gebruikt
worden is hier te vinden.
UIDL
bevel
kan de relatieve naam van het bestand gebruikt worden als
identificatie van het bericht. Dus, als
/home/fred/pop3/lisa/9999
de bestandsnaam
is van een bericht dan kan 9999
als
identificatie (voor het UIDL
bevel) gebruikt
worden.
USER
bevel zal nagaan of de aangegeven
gebruiker bestaat, m.a.w. of er een map bestaat met die naam
onder top
. Voor dit project mag
het PASS
bevel altijd lukken (op voorwaarde
dat al zeker is dat de gebruiker bestaat).
wilma
.
dvutil
,
dvnet
en
dvthread
bibliotheken mogen gebruikt worden. In dvutil
bevinden zich diverse
klassen (bvb. Date
File
,
logstream
) en functies
(bvb. make_daemon
) die vermoedelijk in dit project nuttig
kunnen zijn.
map
,
set
,
vector
, mogen gebruikt worden.
.cc
'', ``.C
'' of
``.cpp
'' te gebruiken. De ``header files'' met declaraties
dienen de suffix ``.h
'' te gebruiken.
Makefile
, dienen zich
in een map stru2.tar
te bevinden.
De volgende reeks van bevelen zal resulteren in
een correct uitvoerbaar programma ``pop3d'':
mkdir test cd test tar xvf ../stru2.tar make clean rm -f pop3d *.o make all
Dv::Thread::Monitor
.
messages
met 57 correcte
e-mail berichten. Dit is nuttig om een test configuratie op te
zetten:
tar zxf $HOME/messages.tar.gz mkdir top mkdir top/lisa cp $HOME/messages/* top/lisa mkdir top/fred cp $HOME/messages/* top/fred
Dv::Props
nuttig.
telnet localhost 9999 +OK pop3d USER fred ...Voor een degelijke test dient men een UA progamma, bvb. mozilla in te stellen zodat de zelfgemaakte pop server gebruikt wordt (vergeet niet het correcte poortnummer op te geven, de standaard poort voor POP3 is immers niet beschikbaar voor gewone gebruikers).
De uiterste indiendatum (stuur tar bestand -- zie hoger -- via e-mail
naar <dvermeir@vub.ac.be>
) is zondag
15/8/2010, 23:59. Een nette afdruk van een document dat
uw ontwerp (hoe en waarom) kort beschrijft moet vóór
die datum op het secretariaat van de vakgroep afgegeven worden.
Later volgt dan een (individuele) mondeling verdediging.
[1] Idem dito voor de server die naar verschillende sockets tegelijk moet kunnen luisteren.
[2] Functionele eisen leggen vast wat het programma moet doen. Niet-functionele eisen leggen vast aan welke andere voorwaarden het programma moet voldoen, bvb. onder welk operating system het moet werken, welke programmeertalen of bibliotheken mogen gebruikt worden, etc.