Hotspots: Admin Pages | Turn-in Site |
Current Links: Cases Final Project Summer 2007
Wu-Tang Cases: Networking in squeak
Our final turn-in (which contains our network code) is posted on our main cases page.
So our idea for the network is awesome. Basically, we made a class (NetworkConnection) that had as few functions as absolutely necessary. Then we overwrote the
doesNotUnderstand: aMessage method so that any messages this object recieved would be SIXX serialized and sent over the network. This class also received serialized SIXX messages and called them on its dependents (which are set to whatever you'd like). This works great for most messages you'd like to send over the network except for images. To counteract this slowness we wrote a class called FormToStringConverter which can be found in RoosterTossers–Model in our final turn-in. FormToStringConverter has a class method that turns image files into strings that can be sent over the network. These strings can then be decoded into forms(the underlying portion of an ImageMorph. see GUI Guide on our main cases page for details) with the other class method in FormToStringConverter.
The folowing description was taken from the '?' comment for the NetworkConnection class and explains how to use it. Along with the ConnectionListener class you have a working network.
NOTE: the NetworkConnection and the ConnectionListener (found in RoosterTossers–Network) must be stepped in order to send and recieve messages. Some examples of a stepper for this purpose are the TestingStepper (found in RoosterTossers–Network) or the ModelStepper (found in RoosterTosser–GUI).
'Message' with a capital 'M' will hereafter refer to the Squeak definition of message which is similar to a procedure, method, or function.
'message' with a lower case 'm' will hereafter refer to the idea of a message you send over a network.
I take Messages sent to me and send them over the connection in a serialized form (currently using the Sixx package).
Sixx has limitations with what objects it can send, namely sending images.
when receiveMessages is called on me I check the connection for new messages and call them on my dependent as Messages. I also return whether or not the connection is still valid. This should be called periodically.
You can call any Message you want on me and I will send it over the connection except for the few Messages I already implement. I will return whether or not the connection is still valid.
connection StringSocket -- used to send messages over the network, after they have been serialized from Messages
dependent Object -- the object the Message will be called on if a message is received over the network
"in an object named client"
| server |
server _ NetworkConnection connectTo: 'aServer' onPort: 2020.
"the server which has a corresponding NetworkConnection called 'client' gets doSomething called on it"
"hi im doing something and i want client to know the results after i finish"
client returnDoSomething: returnValue.
"the client object has returnDoSomething: called on it
note: the above is somewhat misleading. Our code works as a kind of RMI, except there are no
return values for function calls. When you "call a method across the network," your program
continues and the message is NOT sent over the network UNTIL you STEP the appropriate socket.
(in our code, call the function "receiveMessages" on a NetworkConnection to send and receive messages)
The return value of the "RMI" call is not the return value of the function you're acting like
you're calling! Therefore, a function cannot be dependent on results of a network message
that it sends. IE: whenever you have to send messages back and forth over the network, you
MUST split up that communication to multiple functions.
For example, the client calls "requestFriendsOf:for:" on the server, but there is no return
value and no friends are returned. At some point in the future, the server will run that
function and call "retriveFriends:" on the client, giving the client what he requested earlier
(the names of the functions may not match exactly to our code, but they were similar to that).
Some comments about Networking in Squeak in General
(use the function addressForName: if you have a hostname as a string)
- all the networking stuff must be stepped in Squeak (ConnectionQueue, Socket)
- To listen for connections as a server, you need to use the class ConnectionQueue.
- To connect to that server, use the class Socket and the function connectTo:port:
- the address for the connectTo:port: function must be obtained from the NetNameResolver class
The Network Fix
So you're probably wondering why we had to fix the Squeak networking code. Well.... so are we. But
here's what was wrong and how we fixed it:
The StringSocket class can be used to send strings over a network. To create
a StringSocket, pass it a Socket as follows:
stringSockConn := StringSocket on: socket.
Now at this point you have two objects that allow you to send messages over the network, the socket
and the StringSocket. This is a bad idea. So only use the StringSocket and don't hold onto the
socket itself... let the StringSocket keep it.
Here's where the problem is. Once you let go of the original socket, you are dependent on the
StringSocket for your access to the network connection. The underlying socket is a TCP socket
(which means that it has made a connection, as opposed to being connectionless and just sending
messages and hoping they arrive at their destination). TCP connections should be closed down
gracefully, but StringSocket doesn't do that. When you want to close the socket, you'd probably
search through the functions available in the StringSocket class, and you'd find that "destroy"
is the only one that could possibly be used for closing the connection, however, destroy doesn't
close the connection, it cuts the connection without letting the other side know. So the other
side will think it's still connected, but won't be, and will start having errors. There are
This function should call "close" on the underlying socket
- add a "close" function to the StringSocket class
make the function call "close" on the underlying socket before it calls "destroy" on it.
- modify the "destroy" function in the StringSocket class
This is the method we went with.
Now at this point you may be wondering "shouldn't the network connections be able to handle the
case where the network connection fails? Shouldn't it be possible to not barf when the network
wasn't closed really nicely by the other side?"
Well, this is Squeak...
Link to this Page