30SerializeSockets PDF
30SerializeSockets PDF
Serialization / Archiving
• State in memory -- objects
• Write objects to streamed state
- To a disk file, or across the network, or to the system clipboard
- The notion of "address space" does not hold in the streamed form -- there are no pointers. Just a
block of bytes.
• Read
- Read the streamed form, and re-create the object in memory
• There are many words for writing an object to a streamed form
- Writing
- Persisting
- Pickling
- Flattening
- Streaming
- Dehydrate (Rehydrate = read)
- Archiving
ObjectOutputStream
• Create an object output stream wrapped around any other stream. Then can write objects onto that
stream.
• e.g. out = new ObjectOutputStream( <regular file or socket output stream> );
• This is the "decorator" pattern -- wrapping something of interface X in another thing, also of interface X
out.writeObject(obj)
• Suppose "out" is an ObjectOutputStream
• out.writeObject(obj);
• This one line calls the automatic serialization machinery to write out everything rooted at the given
object.
• Classes
- Each written object will be identified by its class -- the reading code will need those same classes
to read the stream.
- The written class should be public (so the receiver can know it)
- The written class should not be inner, since that will try to write the outer object too. It can be a
nested (static) class however.
• Array
- For a collection of things, it may be easier to arrange all the things into a single array that can be
written in one operation.
• Transient
- Fields should be declared transient if they should not be written. They will read back in as null.
• MVC
- Write out the data model, not the view.
- May also want to write out a simplified or canonical version of the data model -- so you can revise
your real internal data model over time, without breaking file compatibility.
out.writeUnshared(obj)
• writeUnshared(obj) -- writes out a fresh copy of the given object, even if that object was previously
written to the stream. However, the no-duplicates property will still hold for objects referenced from
inside the given object.
ObjectInputStream
• Create an ObjectInputStream wrapped around any type of stream
3
in.readObject()
• CT type
- Read back with the same compile time type it was written (Object[] or String[])
• Class
- If a class was written that is not present at read-time, there will be an error.
- If the class has the same name but a changed implementation there will be an error.
- It's safest to serialize classes that are stable everywhere such as Array and Point
Sockets
• Sockets make network connections between machines, but you just read/write/block on them like there
were plain file streams. The Internet is basically built on sockets.
Client Socket
• Make connection to host name "127.0.0.1" or "localhost" (the local machine itself) or
"elaine26.stanford.edu" (machine on the internet) + a port number on that machine.
- Socket toServer = new Socket(host, port); // make connection
- OutputStream out = toServer.getOutputStream(); // write to this
- InputStream in = toServer.getInputStream; // read from this
• Reads will block if there is no data (do not do on swing thread!)
• Writes go through fast, so ok to do on swing thread (could fork off a thread to do it)
• Can wrap each stream in ObjectInputStream/ObjectOutputStream to send whole objects -- a low budget
way to do network i/o without a lot of parsing
Blocking / Flushing
• Reading on a socket when there is no data will block -- so you can't do that on the swing thread
• Likewise, the server blocks in accept(), waiting for new client connections
• Writing on a socket may "buffer" the data to send it all in a big chunk. Use flush() on a stream to force
the accumulated data to go out now. When you close() on a stream when you are done with it, that
does an implicit flush() to send all the data.
for (int i=0 ;i<3; i++ ) { // for testing, handy to make a few at a time
new TickerExample();
}
}
public TickerExample() {
setTitle("Ticker");
JButton button;
button = new JButton("Start Server");
box.add(button);
button.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
doServer();
}
});
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
// Struct object just used for communcation -- sent on the object stream.
// Declared "static", so does not contain a pointer to the outer object --
// that we don't also serialize the whole outer object.
// The contained String and Date objects are both Serializable, otherwise
// the serialization would fail.
public static class Message implements Serializable {
public String text;
public Date date;
public transient TickerExample ticker; // transient = do not send
// Initiate message send -- send both local annd remote (must be on swing thread)
// Wired to text field.
public void doSend() {
Message message = new Message(field.getText(), new Date(), this);
sendLocal(message);
sendRemote(message);
field.setText("");
}
// get input stream to read from server and wrap in object input stream
ObjectInputStream in = new ObjectInputStream(toServer.getInputStream());
System.out.println("client: connected!");
while (true) {
// get object from server; blocks until object arrives.
Message message = (Message) in.readObject();
System.out.println("client: read " + message);
// note message.ticker is null, since "transient"
invokeToGUI(message);
}
}
catch (Exception ex) { // IOException and ClassNotFoundException
ex.printStackTrace();
}
// Could null out client ptr.
// Note that exception breaks out of the while loop,
// thus ending the thread.
}
}
Iterator<ObjectOutputStream> it = outputs.iterator();
while (it.hasNext()) {
ObjectOutputStream out = it.next();
try {
out.writeUnshared(message);
out.flush();