Het gebruik van DirectPlay bij OGO 2.3

Vergelijkbare documenten
UNIVERSITEIT ANTWERPEN FACULTEIT WETENSCHAPPEN DEPARTEMENT WISKUNDE-INFORMATICA OBERON CODE CONVENTIONS

Toets Programmeren, 2YP05 op donderdag 13 november 2008, 09:00-12:00

Programmeren Blok B. Onderwerpen. wstomv/edu/2ip05/ College 8. Tom Verhoeff

Ontwerp van Algoritmen: opgaven weken 3 en 4

Variabelen en statements in ActionScript

rh276a 0 We breiden nu bovenstaand programmafragment uit door assignments toe te voegen aan een nieuwe variabele m, aldus:

Opmerkingen en vragen aan Ultieme vraag: Hoe beïnvloedt dit de winstkansen?

Probleem met dobbelspel. 2IP05: Programmeren Blok A. 5 spelers,2 dobbelstenen. wstomv/edu/2ip05/ Per ronde werpt elke speler 1

Tentamen Objectgeorienteerd Programmeren TI februari Afdeling ST Faculteit EWI TU Delft

Programmeren A. Genetisch Programma voor het Partitie Probleem. begeleiding:

{ specificatie (contract) en toelichting }

Programmeren (1) Examen NAAM:

{ specificatie (contract) en toelichting }

Methode: Verdeel en heers

HOE TEKEN IK EEN OMGEVINGSMODEL

Hoofdstuk 7: Werken met arrays

9 Meer over datatypen

Objective-C Basis. 23 april 2005, Eindhoven Patrick Machielse

Stacks and queues. Hoofdstuk 6

Stacks and queues. Introductie 45. Leerkern 45. Terugkoppeling 49. Uitwerking van de opgaven 49

SQL datadefinitietaal

Turbo Pascal (deel 1)

Uitwerking Tweede deeltentamen Imperatief programmeren - versie 1 Vrijdag 21 oktober 2016, uur

Modelleren en Programmeren

Datatypes Een datatype is de sort van van een waarde van een variabele, veel gebruikte datatypes zijn: String, int, Bool, char en double.

Uitwerking Aanvullend tentamen Imperatief programmeren Woensdag 24 december 2014, uur

Tentamen Object Georiënteerd Programmeren TI januari 2013, Afdeling SCT, Faculteit EWI, TU Delft

Inleiding C++ Coding Conventions

Syntax- (compile), runtime- en logische fouten Binaire operatoren

Modelleren en Programmeren

Vakgroep CW KAHO Sint-Lieven

Vorig college. IN2505-II Berekenbaarheidstheorie College 4. Opsommers versus herkenners (Th. 3.21) Opsommers

4EE11 Project Programmeren voor W. College 3, , Blok D Tom Verhoeff, Software Engineering & Technology, TU/e

Universiteit van Amsterdam FNWI. Voorbeeld van tussentoets Inleiding programmeren

Inleiding Programmeren 2

NAAM: Programmeren 1 Examen 29/08/2012

Toets In2305-ii Embedded Programming Dinsdag 28 November 2006, 15:45-16:30

HOOFDSTUK 3. Imperatief programmeren. 3.1 Stapsgewijs programmeren. 3.2 If Then Else. Module 4 Programmeren

Pascal uitgediept Data structuren

Datastructuren: stapels, rijen en binaire bomen

Zelftest Programmeren in Java

Programmeren in Java les 3

Tentamen Objectgeorienteerd Programmeren IN1205 Voorbeeld

1 Inleiding in Functioneel Programmeren

Tweede college algoritmiek. 12 februari Grafen en bomen

Genetische algoritmen in Java met JGAP

Inleiding Programmeren 2

public boolean equaldates() post: returns true iff there if the list contains at least two BirthDay objects with the same daynumber

Ontwerp van Informatiesystemen

Totaal

Als een PSD selecties bevat, deelt de lijn van het programma zich op met de verschillende antwoorden op het vraagstuk.

Aanvullende toets Gameprogrammeren (INFOB1GP) Woensdag 24 december 2014, uur

Access voor beginners - hoofdstuk 25

TCP-IP message van partner PLC naar Alarmsysteem met als inhoud alarmen en analoge waarden in Format code 01.

Modelleren en Programmeren

Programmeren in Java 3

Tweede deeltentamen Mobiel programmeren - versie 1 Vrijdag 2 februari 2018, uur

Derde Delphi Programma verkenning

Creatief met Claim Check VNSG Tips & Tricks juni 2017

Waarden persistent (blijvend) opslaan gaat in bestanden (files). Lege tekst: eof

Zeef van Eratosthenes

Tutorial 1, Delphi: Geldspraak

6.3 VBA Syntax Instructie. Wij gaan de Visual Basic Editor opnieuw openen, om de instructie die wij zojuist getypt hebben, nader te bekijken.

Een inleiding in de Unified Modeling Language 67

Modelleren en Programmeren

Uniforme Pensioen Aangifte (UPA)

Lab Webdesign: Javascript 3 maart 2008


Uitgebreide uitwerking Tentamen Complexiteit, mei 2007

HOOfDsTuk 1 Objecten en klassen

Datastructuren Werkcollege Intro

INFITT01 Internettechnologie WEEK 2

In de tweede regel plaatsen we in het gereserveerde stukje geheugen een getal.

Achtste college algoritmiek. 8 april Dynamisch Programmeren

Xelion ESPA koppeling Handleiding Beheer V1.6

6.2 VBA Syntax. Inleiding Visual Basic

Zelftest Programmeren in PL/I

Organiseer uw verschillende SOAP services in één scenario

Programmeren in Java 3

Zelftest Inleiding Programmeren

NHibernate als ORM oplossing

Informatica: C# WPO 7

Visual Basic.NET. Visual Basic.NET. M. den Besten 0.3 VB. NET

Een gelinkte lijst in C#

Hoofdstuk 7: Werken met arrays

EE1400: Programmeren in C BSc. EE, 1e jaar, , 3e college

In deze aflevering van deze serie zal ik proberen een groot gebrek van Turbo Pascal weg te nemen, namelijk het gemis aan Random Access Files.

Gegevensopslag in databouwstenen

Derde deeltentamen Imperatief programmeren - versie 1 Vrijdag 6 november 2015, uur

Bouwstenen voor PSE. Datatypes en Datastructuren

Modelleren en Programmeren

Leren Programmeren met Visual Basic 6.0 Les 3+4. Hoofdstuk 4 : De Selectie

Verzamelingen, Lijsten, Functioneel Programmeren

Programmeeropdracht 2 Toernooi Algoritmiek, voorjaar 2019

Data Definition Language

Datastructuren: stapels, rijen en binaire bomen

Technical Note. API Beschrijving Aangetekend Mailen

Examen Datastructuren en Algoritmen II

Deel 1: Arduino kennismaking. Wat is een microcontroller, structuur van een programma, syntax,

Les 15 : updaten van gegevens in de database (deel2).

Transcriptie:

rh271 0 Het gebruik van DirectPlay bij OGO 2.3 0 Inleiding De objectklasse DXPlay biedt primitieven waarmee een collectie processen een (zogenaamde) groep kunnen vormen. Ieder proces dat aldus tot een groep behoort kan vervolgens berichten versturen naar ieder van de andere processen in dezelfde groep. Communicatie tussen de processen in een groep verloopt dus paarsgewijs. De samenstelling van een groep staat aan alle processen in de groep ter beschikking. De processen kunnen zich in verschillende machines bevinden; deze machines zijn dan met elkaar verbonden via een netwerk. DXPlay verzorgt de communicatie via dit netwerk. In het vervolg gaan we er van uit dat ieder proces zich in een eigen machine bevindt. Voor het gebruik van DXPlay volstaat, per groepslid, het gebruik van slechts één object uit deze klasse. Hiertoe is het voldoende één variabele van type DXPlay in het programma te declareren. In het vervolg noemen we deze variabele DXGroup. Dit is een lokale variabele van het proces: ieder proces in de groep heeft dus een eigen variabele DXGroup, waarin voor het proces de samenstelling van de groep wordt geadministreerd. 1 Protocol Ieder proces doorloopt drie fasen: toetreding tot de groep, het eigenlijke spel waarin de processen in de groep met elkaar communiceren, en uittreding uit de groep. Het (eigenlijke) spel kan pas nen na eindiging van de toetredingsfase. Omdat de onderliggende netwerkcommunicatie asynchroon is, is eindiging van de toetredingsfase echter niet eenvoudig detecteerbaar. Hiermee kan op allerlei manieren rekening worden gehouden: 0. Het van het spel wordt in elk proces gesynchoniseerd door middel van een dialoogje met de externe gebruiker van (de machine van) het proces. De gebruiker sluit dit dialoogje pas als hem duidelijk is dat alle processen zijn toegetreden. Een mogelijke variant hierop is dat zo n dialoogje met slechts één proces plaatsvindt en dat de andere processen een speciaal start -bericht van dit ene proces afwachten. 1. Via een openingsdialoogje wordt aan elk proces meegedeeld hoe groot

rh271 1 de groep zal zijn; het proces t nu pas aan het spel als de geadministreerde groep de aldus ingegeven omvang heeft. Het als constante in het programma opnemen van de groepsgrootte is niet wenselijk: het feitelijke aantal spelers moet variabel zijn. 2. Het eigenlijke spel is zo ingericht dat er tijdens het spel nog processen dat is: spelers kunnen toetreden. Dit is bepaald niet gemakkelijk correct te programmeren en wordt daarom afgeraden. De beschrijving in de volgende paragrafen is gebaseerd op het gebruik van fasesynchronisatie en dus op de veronderstelling dat de samenstelling van de groep tijdens het eigenlijke spel niet wordt gewijzigd. 2 Groepsadministratie De objectvariabele DXGroup heeft een attribuut Players waarvan de waarde een lijst van procesbeschrijvingen is. (In het jargon van DirectPlay heten de processen die tot één groep behoren players.) De lijst Players representeert derhalve de hele groep: ieder proces in de groep komt er één keer in voor, ook het proces waartoe DXGroup zelf behoort. Ieder proces in de groep heeft een variabele DXGroup en dus heeft ieder proces in de groep een groepslijst DXGroup.Players. De volgorde waarin de processen in deze lijst voorkomen is niet gespecificeerd; daarom mag niet worden aangenomen dat deze volgorde in alle processen dezelfde zou zijn! De groepslijst Players heeft een integer attribuut Count dat de lengte van de lijst (en dus de omvang van de groep) weergeeft. Verder zijn de elementen van de lijst genummerd vanaf 0 tot en zonder Count : aldus is Players[ i] de beschrijving van het groepslid op positie i in de lijst, voor 0 i<count. (Deze nummering vormt zo dus een lokale naamgeving die per proces anders kan zijn! van de groepsleden.) De elementen van de lijst Players zijn objecten van type TDXPlayPlayer. Ieder object van dit type heeft een attribuut ID dat het door het object voorgestelde proces identificeert. Dit wordt uitsluitend gebruikt om de bestemming van een te verzenden bericht aan te geven; bij ontvangst van berichten wordt de afzender weergegeven door een object van type TDXPlayPlayer 0. Verder heeft zo n object een attribuut Name, vantype string, dat bij het toetreden tot de groep wordt geïnitialiseerd met de in de openingsdialoog zie volgende paragraaf opgegeven (externe) spelersnaam. Het attribuut 0 Hoezo, inconsequent?

rh271 2 Name kan, bijvoorbeeld, worden gebruikt om de spelersnaam op het scherm af te beelden. Het versturen van een bericht naar het groepslid met lokaal nummer i, met 0 i < DXGroup.Players.Count, komt derhalve neer op het versturen van een bericht naar het proces DXGroup.Players[ i].id. 3 Toetreding Ten behoeve van de toetreding heeft DXGroup als attribuut een procedure 1 Open en een event genaamd OnOpen. De procedure Open heeft geen parameters. Na uitvoering van DXGroup.Open maakt het proces deel uit van de groep en is de verwerking hiervan in de groepsadministratie van alle groepsleden in gang gezet; deze verwerking hoeft op zo n moment echter nog niet te zijn voltooid. De voltooiing van (de administratieve afwikkeling van) de toetreding wordt aan het toegetreden proces teruggemeld via het event OnOpen. Zodra dit event optreedt is de groepsadministratie van het toegetreden proces geïnitialiseerd. Voor het aan de andere groepsleden signaleren van een toetreding is er een event OnAddPlayer. De betekenis hiervan is dat er een proces tot de groep is toegetreden. In de aan dit event gebonden afhandelingsprocedure representeert de parameter Player het nieuw toegetreden proces. Tevens geldt dat, ten tijde van het optreden van de event OnAddPlayer, de waarde van deze parameter al in de groepsadministratie DXGroup.Players is opgenomen. Dit behoeft men dus niet zelf te programmeren! Dit event wordt getriggerd bij alle leden van de groep, het zojuist toegetreden proces incluis. Het uiteindelijke effect van DXGroup.Open is dus dat het nieuwe lid in de groepsadministratie van alle groepsleden voorkomt, dat bij alle groepsleden het event OnAddPlayer is getriggerd en dat bij het nieuwe groepslid het event OnOpen is getriggerd. Als deze events worden gebruikt om gegevens over de groepsleden te verzamelen, dient men er dus rekening mee te worden gehouden dat bij het nieuwe groepslid beide events worden getriggerd, in een niet nader gespecificeerde volgorde. De uitvoering van DXGroup.Open veroorzaakt ook een openingsdialoog met de gebruiker waarin het te gebruiken netwerkprotocol kan worden ingesteld altijd IPX en waarin de naam van de speler kan worden ingevoerd; deze naam wordt toegekend aan het Name -attribuut van alle objecten die deze speler representeren. 1 in OO-jargon: methode

rh271 3 4 Representatie van berichten Een lid van de groep kan berichten zenden aan elk lid van de groep. Vaak zal het voorkomen dat er berichten van verschillende typen worden gebruikt. Om berichten aan de ontvangstzijde naar type te kunnen onderscheiden biedt DirectPlay een (primitieve) faciliteit. In het programma kunnen, zoveel als wenselijk, definities voor berichttypen worden opgenomen. Om genoemde faciliteit te kunnen gebruiken moet elk berichttype een recordtype zijn waarvan het eerste veld type DWORD heeft. Het (Delphi-)type DWORD kan geheeltallige waarden bevatten (en heeft de eigenschap dat het geheugenbeslag ervan in alle machines binnen de groep gelijk is, zodat ondubbelzinnige communicatie mogelijk is). Dit eerste veld van zo n record wordt gebruikt om het berichttype aan te geven; het ligt dan ook voor de hand dit eerste veld MessType (of iets dergelijks) te dopen. Voor het coderen van berichttypen is oplopende nummering het gemakkelijkst; via een constantendefinitie kan men deze nummers aan namen binden. Met het oog op de snelheid van berichtenverzending wordt aanbevolen de gebruikte berichttypen redelijk klein te houden. voorbeeld: Hier zijn definities voor vier typen berichten, voor het verzenden van een leeg bericht, een enkel geheel getal, twee gehele getallen, en een rijtje van maximaal 40 characters: const EMP MESS = 0; INT MESS = 1; INT2 MESS = 2; STR MESS = 3; ML = 40; type MyString = array [0..ML-1] of char; TDXEmpMess = record MessType: DWORD; TDXIntMess = record MessType: DWORD; Value: Integer; TDXInt2Mess = record MessType: DWORD; Val0,Val1: Integer;

rh271 4 TDXStrMess = record MessType: DWORD; Len: Integer; Data: MyString; Bij berichten van type TDXEmpMess wordt het veld MessType altijd geïnitialiseerd met de constante EMP MESS, bij type TDXIntMess wordt altijd INT MESS gebruikt, enzovoort. Een invariant van alle berichten van type TDXStrMess zal vermoedelijk zijn: 0 Len ML. opmerking: Delphi kent een standaard datatype string ; omdat dit is geïmplementeerd met behulp van pointers kunnen velden van type string echter niet in berichttypen worden gebruikt: het verzenden van pointers is zinloos. 5 Zenden De DirectPlay procedures voor zenden en ontvangen van berichten hebben een parameter van het type pointer om berichten over te dragen. Daarom moeten in de programma s waarin deze zend- en ontvangprocedures worden gebruikt pointervariabelen worden gedeclareerd. Voor verzending van berichten kan hiertoe voor ieder berichttype een pointervariabele van overeenkomstig type worden gebruikt. Bij ontvangst van een bericht is niet (syntactisch) bekend welk berichttype het zal hebben; hiervoor wordt het algemene type Pointer gebruikt en de (al genoemde) DirectPlay faciliteit om berichttypen te onderscheiden. Dit wordt met voorbeelden verduidelijkt. voorbeeld: Voor sommige van de in het vorige voorbeeld opgevoerde berichttypen geven we hier een procedure om een bericht van zo n type aan een proces dest, van type TDXPlayPlayer, te zenden. Om zo n procedure toe te passen op element nummer i van de groepslijst vult men voor dest dus DXGroup.Players[ i] in. De Delphi-procedure GetMem is vergelijkbaar met new in standaard Pascal, zij het dat GetMem een extra parameter voor de afmeting van de te creëren variabele heeft; met behulp van de standaardfunctie SizeOf kan deze afmeting uit het berichttype worden bepaald. De Delphi-procedure FreeMem is de inverse van GetMem.

rh271 5 procedure SendEmpty(dest: TDXPlayPlayer); { send an empty message to player "dest" } var mess: ^TDXEmpMess; size: Integer; size := SizeOf(TDXEmpMess) ; GetMem(mess,size) ; try mess^.messtype := EMP MESS ; DXGroup.SendMessage(dest.ID, mess, size) finally FreeMem(mess) end end {SendEmpty}; procedure SendIntegers(x,y: Integer; dest: TDXPlayPlayer); { send "x" and "y" to player "dest" } var mess: ^TDXInt2Mess; size: Integer; size := SizeOf(TDXInt2Mess) ; GetMem(mess,size) ; try mess^.messtype := INT2 MESS ; mess^.val0 := x ; mess^.val1 := y ; DXGroup.SendMessage(dest.ID, mess, size) finally FreeMem(mess) end end {SendIntegers}; procedure SendMyString(n: Integer; s: MyString; dest: TDXPlayPlayer); { send "s[0..n)" to player "dest" } { PRE: 0 <= n <= ML } var mess: ^TDXStrMess; size: Integer; size := SizeOf(TDXStrMess) ; GetMem(mess,size) ; try mess^.messtype := STR MESS ; mess^.len := n ; mess^.data := s ; DXGroup.SendMessage(dest.ID, mess, size) finally FreeMem(mess) end end {SendMyString};

rh271 6 6 Ontvangen Bij aankomst van een bericht wordt het event OnMessage getriggerd en wordt de hieraan gebonden procedure uitgevoerd. Als er meerdere berichttypen worden gebruikt dient in deze procedure het gevalsonderscheid naar berichttypen te worden gemaakt. (Zelfs als er maar één berichttype wordt gebruikt kost het weinig om dit ene type te controleren!) De afhandelingsprocedure voor OnMessage heeft een parameter van het algemene en abstracte type Pointer, die het ontvangen bericht voorstelt. Om dit bericht correct te interpreteren moet het bericht worden opgevat als een bericht van het juiste type. Als mess zo n pointer is, is messˆ het bericht zelf; door er de naam van het betreffende berichttype op toe te passen, als ware het een functie, wordt dit bericht verondersteld van dat type te zijn 2 en kunnen de bij dat type behorende operaties worden toegepast. voorbeeld: Door TDXEmpMess(messˆ) wordt messˆ opgevat als een leeg bericht, door TDXStrMess(messˆ) wordt messˆ opgevat als een stringbericht, enzovoort. Deze manier van type-interpretatie is alleen correct als het bericht ook daadwerkelijk van het juiste type is. Om dit te garanderen moet het eerste recordveld, dat immers het berichttype bevat, worden geïnspecteerd. Hiertoe bevat DXPlay een functie DXPlayMessageType die, bij toepassing op een pointer naar enig bericht, het type van dat bericht oplevert. Als mess een pointer naar een bericht is, is DXPlayMessageType(mess) de waarde messˆ.messtype, dat is, het type van het bericht messˆ. (Dit vereist natuurlijk wel dat alle gebruikte berichttypen een eerste veld hebben dat het berichttype bevat.) voorbeeld: Het ligt voor de hand dat we voor elk mogelijk berichttype een procedure schrijven voor de afhandeling van ontvangen berichten van dat type. Als we dat doen bestaat de algemene, aan het event OnMessage gebonden, afhandelingsprocedure slechts uit een gevalsonderscheid naar berichttypen, plus aanroepen van de betreffende procedures. Voor de berichttypen uit de vorige voorbeelden zou de afhandelingsprocedure er zó uit kunnen zien de parameter sdr kan worden genegeerd; de parameter size lijkt ook overbodig : 2 Dit staat bekend als type casting. Deze programmeerpraktijk is dubieus maar, mits zorgvuldig toegepast, wel efficiënt.

rh271 7 procedure AnyMessage(sdr: TObject; sndr: TDXPlayPlayer; mess: Pointer; size: Integer); var s: MyString; x,y,n: Integer; case DXPlayMessageType(mess) of EMP MESS: ReceiveEmpty(sndr) INT MESS: x := TDXIntMess(mess^).Value ; ReceiveInteger(sndr, x) INT2 MESS: x := TDXInt2Mess(mess^).Val0 ; y := TDXInt2Mess(mess^).Val1 ; ReceiveIntegers(sndr, x, y) STR MESS: n := TDXStrMess(mess^).Len ; s := TDXStrMess(mess^).Data ; ReceiveMyString(sndr, n, s) else { something is wrong: }... end {case} end {AnyMessage}; Hierbij zijn de procedures waarvan de naam t met Receive dus de voor alle berichttypen voorziene afhandelingsprocedures. Merk op dat het terugzenden van een leeg bericht, bij wijze van ontvangstbevestiging, eenvoudig kan worden toegevoegd als een aanroep SendEmpty(sndr), waar dat maar gewenst is. 7 Uittreding Na beëindiging van het spel treedt een proces uit de groep door aanroep van de procedure DXGroup.Close. Dit leidt uiteindelijk tot het triggeren van een event OnClose bij het uitgetreden proces en leidt bij elk van de overblijvende groepsleden tot het triggeren van een event OnDeletePlayer. Deze events zijn alleen van belang als processen tijdens het eigenlijke spel kunnen uittreden.

rh271 8 Als het spel voor alle groepsleden tegelijkertijd eindigt hoeft voor deze events niet in afhandelingsprocedures te worden voorzien. 8 Overige attributen De objectvariabele DXGroup heeft nog een attribuut LocalPlayer, behorend tot type TDXPlayPlayer, dat het proces representeert waartoe DXGroup behoort. Ieder object van type TDXPlayPlayer heeft nog een boolean attribuut RemotePlayer dat equivalent is met het proces is niet LocalPlayer 3. Derhalve zijn de volgende relaties invariant: DXGroup.LocalPlayer.RemotePlayer, en, voor alle i met 0 i < DXGroup.Players.Count : DXGroup.Players[ i].remoteplayer DXGroup.Players[ i] DXGroup.LocalPlayer. Tenslotte geldt dat er een (unieke) i is, met 0 i < DXGroup.Players.Count, waarvoor geldt: DXGroup.Players[ i] = DXGroup.LocalPlayer. Eindhoven, 26 april 2001 Rob R. Hoogerwoord faculteit der Wiskunde en Informatica Technische Universiteit Eindhoven postbus 513 5600 MB Eindhoven 3 Merk op hoe onhandig de identifiers hier zijn gekozen: RemotePlayer is een boolean en LocalPlayer is een procesobject. Pas dus op!