8  Thursday Afternoon: A Networking Application

Whose Line is It, Anyway?
By Shriram

Say, you are part of a group of Shakespeare fans who “read” the Bard’s plays over the Internet. You like reading Shakespeare (who doesn’t?), but you hate typing in all those “quothe”s and “thine”s and what not (who doesn’t?). Being a Seasoned Schemer, you’re too smart to get suckered into typing all that text. Instead, you want to write an Internet agent that does the work for you. Let’s assume there are only three roles in the dialogs we want to read: yours and two others.


Exercise

Exercise 8.1.   To wit, you will write a procedure with the following contract:

;; serve : Symbol Number Dialog String Number String Number  →  true

The arguments to serve have the following meaning:

The supplementary teachpack provides two functions:

Add the teachpack
hamsup.scm

;; install-listener : Number (Sexpr  →  true)  →  true
;; installs a procedure that is invoked each time when a
;; message shows up on a specific port number
(define (install-listener listener) ...)

;; send-message : String Number Sexpr  →  true
;; send a message to a machine at a certain port 
(define (send-message machine port msg) ...)

Here are some more specifics on install-listener. The procedure given to install-listener receives the content of the message, which can be any S-expression. To standardize, we will use the following packet format:

  (list symbol 
        (list string) 
        number)

The first component is the name of a character; the second is a list of strings indicating the lines in a part for that character; and the third is a counter, which we will discuss below. When your agent receives a message, it should print the name and dialog that your Internet buddies sent.

Hint: The functions display and , available in the io teachpack, which we installed for exercise 7.6. The first writes an S-expression to a port and produces true; the second writes a new line to a port and produces true, too. A TA will help you put these together.

The number dictates which part of the dialog (assumed to be shared by all three agents) comes next—indices begin at 0. Therefore, your agent needs to look up the dialog to determine who is supposed to say that part. If it’s someone else, do nothing (the agent can just return a dummy value, like 'do-nothing). Otherwise, your agent needs to transmit the Bard’s eternal words. It does this by using the library procedure

  send-message : machine-name port-number s-expression  →  <ignore>

It needs to send a message to each of the other two machine/port combinations that were given as arguments to serve. The s-expression in this case is a packet in the format specified above. Important: The number your agent specifies in the packet it transmits must be one bigger than the number it received!

This process works well once initiated, but it’s impossible to initiate! (A message only gets sent in response to an incoming one, so if you never receive a message....) Therefore, we shall designate one kind of packet as special: ones of the form

  (fake () 0)

If the number field is 0, that means the message is being sent only to initiate the dialog. Ideally, you should not bother printing out the character’s name and dialog in this case (since they are nonsensical values), but don’t worry about this initially.

As an example, a dialog using the Hamlet prose might look like this:

machineG: running

(serve
 'GUILDENSTERN 7000 dialog "machineR" 7001 "machineH" 7002)

machineR: running

(serve
 'ROSENCRANTZ 7001 dialog "machineG" 7000 "machineH" 7002)

machineH: running

(serve 'HAMLET 7002 dialog "machineR" 7001 "machineG" 7000)

Someone executes

(send-message "machineG" 7000 '(fake () 0))

(sending the same message to the other two should have no effect).

On receiving this, machineG transmits

(list 'GUILDENSTERN '("My honoured lord!") 1)

to the other two; machineR then transmits

(list 'ROSENCRANTZ '("My most dear lord!") 2)

to the other two; machineH then transmits

(list 'HAMLET 
      '("My excellent good friends! How dost thou,"
         "Guildenstern? Ah, Rosencrantz! Good lads, how do ye both?")
      3)

to the other two; machineG then transmits

(list 'ROSENCRANTZ 
      '("As the indifferent children of the earth.")
      4)

to the other two; and so forth. 


Notes on Machines, Ports and Debugging