Java Reference
In-Depth Information
DataOutputStream
BufferedOutputStream
OutputStream
3.14 (8 bytes)
3.14
writeDouble(3.14)
writeInt(343)
343 (4 bytes)
343
14 bytes
800 (2 bytes)
800
writeShort(800)
Network
DataInputStream
BufferedInputStream
InputStream
readDouble()
3.14 (8 bytes)
3.14
343 (4 bytes)
343
14 bytes
readInt()
800 (2 bytes)
800
readShort()
Figure 3.1: Stream composition.
3.2
Composing I/O Streams
Java's stream classes can be composed to provide powerful encoding and decoding facilities.
For example, we can wrap the OutputStream of a Socket instance in a BufferedOutputStream
instance to improve performance by buffering bytes temporarily and flushing them to the
underlying channel all at once. We can then wrap that instance in a DataOutputStream to send
primitive data types. We would code this composition as follows:
Socket socket = new Socket(server, port);
DataOutputStream out = new DataOutputStream(
new BufferedOutputStream(socket.getOutputStream()));
Figure 3.1 demonstrates this composition. Here, we write our primitive data values, one by
one, to DataOutputStream , which writes the binary data to BufferedOutputStream , which buffers
the data from the three writes and then writes once to the socket OutputStream , which controls
writing to the network. We create a parallel composition for the InputStream on the other
endpoint to eciently receive primitive data types.
A complete description of the Java I/O API is beyond the scope of this text; however, Table
3.1 provides a list of some of the relevant Java I/O classes as a starting point for exploiting its
capabilities.
3.3
Framing and Parsing
Converting data to wire format is of course only half the story; the original information must
be recovered at the receiver from the transmitted sequence of bytes. Application protocols
typically deal with discrete messages, which are viewed as collections of fields. Framing refers
to the problem of enabling the receiver to locate the beginning and end of the message in
 
Search WWH ::




Custom Search