-- occam masterclass demo 3: a client-server system -- Compile with: kroc -d -di q3.occ #INCLUDE "course.module" --** A concurrent dice-rolling application. -- Imagine this is part of some complicated multiplayer game... --{{{ types --* Requests to the random number generator. PROTOCOL DICE.REQ CASE --* Roll a die for me. -- The number rolled will be returned along the resp channel. roll --* I'm done; disconnect done : --* Interface to the dice roller. CHAN TYPE DICE.CT MOBILE RECORD --* Requests... CHAN DICE.REQ req?: --* ... and responses CHAN INT resp!: : --}}} --{{{ PROC roller (CHAN INT out!) --* Generate a stream of random numbers between 1 and 6 inclusive. PROC roller (CHAN INT out!) INITIAL INT seed IS 25091981: WHILE TRUE INT n: SEQ n, seed := random (6, seed) out ! n + 1 : --}}} --{{{ PROC server (CHAN DICE.CT? register?) PROC server (CHAN DICE.CT? register?) CHAN INT numbers: PAR roller (numbers!) --{{{ registration code VAL INT MAX.CLIENTS IS 20: -- The server ends received from the client processes INITIAL MOBILE []DICE.CT? ends IS MOBILE [MAX.CLIENTS]DICE.CT?: -- Whether each slot in the "ends" array is in use -- initially set to FALSE INITIAL [MAX.CLIENTS]BOOL in.use IS [i = 0 FOR MAX.CLIENTS | FALSE]: WHILE TRUE ALT DICE.CT? new.end: register ? new.end --{{{ register new end -- ... IF IF i = 0 FOR MAX.CLIENTS NOT in.use[i] SEQ in.use[i] := TRUE ends[i] := new.end --}}} ALT i = 0 FOR MAX.CLIENTS in.use[i] & ends[i][req] ? CASE roll --{{{ return number -- ... INT n: SEQ numbers ? n ends[i][resp] ! n --}}} done --{{{ unregister this end in.use[i] := FALSE -- ... --}}} --}}} : --}}} --{{{ PROC client (VAL INT id, SHARED CHAN DICE.CT? register!, SHARED CHAN BYTE out!) PROC client (VAL INT id, SHARED CHAN DICE.CT? register!, SHARED CHAN BYTE out!) DICE.CT! cli: DICE.CT? svr: SEQ --{{{ create DICE.CT and register the server end cli, svr := MOBILE DICE.CT CLAIM register! register ! svr --}}} --{{{ make a number of requests SEQ i = 0 FOR 5 INT n: SEQ cli[req] ! roll cli[resp] ? n CLAIM out! SEQ out.string ("Client #", 0, out!) out.int (id, 0, out!) out.string (" rolled a ", 0, out!) out.int (n, 0, out!) out ! '*n' --}}} : --}}} PROC q3 (SHARED CHAN BYTE out!) SHARED! CHAN DICE.CT? register: PAR server (register?) PAR i = 0 FOR 5 client (i, register!, out!) :