To write a server, we will be using
the universe
form. It is similar to big-bang,
and we'll be interested in the following events: new
connections, disconnections, and messages.
Here's how we'll be using those events:
New connection events happen when a client connects to the
server, and are handled by the on-new
clause.
The contract for functions given to on-new
is:
UniverseState IWorld -> Bundle
Disconnections happen when a client disconnects from the
server, and are handled by the on-disconnect
clause.
The contract for functions given to on-disconnect
is:
UniverseState IWorld -> Bundle
Messages are sent from the clients to the server, and are
handled by the on-msg
clause.
The contract for functions given to on-msg
is:
UniverseState IWorld Message -> Bundle
The UniverseState
is very similar
to the World
State for local programs, only
that it keeps track of the State of the entire Universe, not just
a World. At the very least, the UniverseState
will have to contain all the client connections (a.k.a. IWorlds),
to be able to send Messages from any client to any client.
An IWorld
is a datatype
internal to the universe teachpack that describes a client connection.
For the purpose of this lab, there is one operation you can perform
on an IWorld, which is iworld-name
.
iworld-name
takes an IWorld
and returns a String which represents the name of the client
in the specific client connection (a.k.a. IWorld).
iworld-name
will return, for a given IWorld
(a.k.a. client connection), exactly the name specified
by the name
clause
of big-bang
in the specific client.
A Bundle
is a collection of three things:
Bundle
is created using
the make-bundle
function,
whose contract is:
make-bundle:UniverseState [Listof Mail] [Listof IWorld]
->Bundle
The server we design will keep track of the connected clients, and any time a client sends a message to the server, which will be a String, the server sends a Mail to each connected client (including the sending client) that contains a String containing both the client's name and the message sent by the client.
To create a Mail value, themake-mail
function is
used, whose contract is:
IWorld Message -> Mail
For example, if the client with the name "vlad" sends the message "hello" to the server, then each client should receive a Mail value from the server that contains the String "vlad: hello".
In addition, the server should send a Message (as before, a String) to each connected client whenever a client connects or disconnects.
For example, if the client "chadwick" connects, each client will receive the message "chadwick connected.", and if it later disconnects, each (still-connected) client will receive the message "chadwick disconnected."
handle-new
handles new connections to the server. ;; handle-new : UniverseState IWorld -> Bundle
handle-disconnect
handles clients that disconnect from the server. ;; handle-disconnect : UniverseState IWorld -> Bundle
handle-msg
handles new messages from clients to the server. ;; handle-disconnect : UniverseState IWorld String -> Bundle
universe
function is used:
INITIAL-UNIVERSE is the first UniverseState, when there are no connected clients.(universe INITIAL-UNIVERSE (on-msg handle-msg) (on-new handle-new) (on-disconnect handle-disconnect))
Note: To launch more than one client from the same machine,
use launch-many-worlds
:
(launch-many-worlds (run "chadwick") (run "vlad"))
Right now the simple chat server that we've provided above can only interact with clients that send around Strings as Messages (i.e., clients like the "initial client" we provided you with in lab). You will have to extend this server so that it can handle a Message that is a non-empty list of Strings so your server can interact with the advanced client you developed in lab. As in lab, the first String defines what type of Message is being described, and the meaning of any other strings in the list depend on the type. See Exercises 4 through 7 and Exercise 11 for information on the types of messages you might want to support. (We suggest you also look at the data definitions for incoming and outgoing messages in the "advanced chat server" implementation we provided on the hw10h page.)
To avoid spoofing, the following protocol should be used by the
server to communicate to the clients:
When clients send "MSG" Messages to the server,
they do not send a <name>—the server adds
the appropriate client name before sending the messages to clients.
In other words, the only Message sent from clients to the server
at this point is (list "MSG" <msg>);
the other Messages are generated server-side for connections and
disconnections. For other, later extensions, the server should add
names as appropriate to Messages.
We suggest that in future extensions, the second position in the list
(i.e. after the Message type) is reserved for the client name, so that
adding it is a uniform operation.