Part III

Interprocess Communication & Sockets

Processes on different computers share no memory, so the only way they can cooperate is by sending each other messages. This Part covers the building blocks every later topic stands on: the TCP/IP stack, TCP and UDP, ports and sockets in Java, how data is flattened into bytes (marshalling), multicast, and overlay networks.

  • You willcompare TCP and UDP along named dimensions, the classic 3-mark exam question.
  • You willread and write Java TCP and UDP client and server code, call by call.
  • You willexplain the failure models of UDP, TCP and IP multicast, and why TCP is not fully reliable.
  • You willmarshal one record in CDR, Java serialization, XML and JSON, and argue XML vs JSON.
3.1

Protocols and the TCP/IP Stack

The problem. Two programs running on two different computers cannot read each other's variables: each has its own private memory. If they are to cooperate, one must put data into a message, hand it to the network, and the other must pick it up. Interprocess communication (IPC) is the name for how processes on different computers exchange data in this way.

IPC is the foundation for everything higher up in the subject. Remote method invocation (Part VI), group communication and publish-subscribe (Part VII), the NFS file system (Part VIII) and DNS (Part IX) are all built from the primitives in this Part: UDP and TCP sockets, marshalling, multicast and overlays. The picture shows where those primitives sit.

Applications and services Middleware: remote invocation, indirect communication IPC primitives: sockets, message passing, multicast, overlays UDP and TCP: the transport layer IP over the underlying networks Parts VI and VII this Part networking background
Each layer is built on the one below it. Middleware (violet) gives programmers friendly abstractions such as calling a method on a remote object, but underneath it uses exactly the primitives in the teal band. The bottom two bands are the networking background you need first, in this section and 3.2.

Clients, servers and protocols exam

Client-server computing has three elements. A client is a process that requests a service. A server is a process that offers a service to one or more clients. The two are joined by a network. (A process is simply a running program.)

For the two to understand each other, sending bytes is not enough: they must agree in advance on what the bytes mean and when to send them. That agreement is a protocol.

Definition · protocol

A protocol is a well-known set of rules and formats to be used for communication between processes in order to perform a given task (CDK §3.3.4). It defines two things:

  1. the sequence of messages to be exchanged: who sends what and when, so that sending and receiving are coordinated;
  2. the format of the data in those messages: how it is encoded.

Humans follow protocols too, but theirs are unspoken (eye contact, gestures, taking turns to talk). Computers need the rules spelled out exactly. Because an agreed protocol says nothing about the programming language or the machine, a Java program can talk to a C program as long as both follow it.

The course example is Buyya's Math server. It reads one line of text of the form operator:first:second, such as +:12:21, and replies with one line holding the answer.

client Math server 1 · "+:12:21" 2 · "33" computes 12 + 21 1 Sequence of messages Who sends what, and when: the client sends one request line, the server replies with one. 2 Format of the data How the request line is encoded: operator : first : second e.g. + e.g. 12 e.g. 21
A protocol = a message sequence + a data format. Blue is the client and red the server, and these colours stay the same for the whole of this Part. If either side breaks either half of the agreement (sends two lines, or writes 12+21), the other side misreads it or waits forever.

The TCP/IP stack exam

Sockets, the programming interface this Part teaches, live inside the TCP/IP protocol stack, so it helps to know what each layer does. A layer is a piece of networking software that offers a service to the layer above and uses the service of the layer below. The four layers, from the top down, are:

LAYER EXAMPLES UNIT OF DATA Application HTTP, FTP, Telnet, SMTP, DNS, Zoom messages Transport TCP, UDP · interface: sockets segments / datagrams Internet / Network IP (v4, v6) · best-effort routing IP datagrams Physical / Link Ethernet, WiFi, device drivers frames finds the PROCESS (port) finds the HOST (IP addr.) Each row uses the row below it and serves the row above it.
Notice the split between the two middle layers. The Internet layer gets data to the right host (computer) using its IP address; the transport layer then gets it to the right process on that host using a port number (3.3). Sockets are the programming interface of the transport layer.
LayerWhat it doesExamplesUnit
ApplicationMessage exchange between standard or user applicationsHTTP, FTP, Telnet, SMTP, DNS, ZoomMessages
TransportDelivers data to a specific process on a remote host using ports. Its programming interface is socketsTCP, UDPSegments / datagrams
Internet / NetworkDelivers packets to a remote host by IP address, routing across networks. Best-effort onlyIP (v4, v6)IP datagrams
Physical / LinkTransmits the signals or frames carrying the data between directly connected nodesEthernet, WiFi, device driversFrames

Encapsulation: how data moves through the stack

Data moves through the stack by encapsulation. On the way down, each layer wraps what it was given in its own header (a block of control information such as addresses) and passes the bigger package down. On the way up at the receiver, each layer reads and strips off its own header and passes the rest up. Step through it:

Encapsulation: down one stack, up the other
SENDING HOST RECEIVING HOST Application Transport Internet Link Application Transport Internet Link physical network: bits on the wire "hello" TCP/UDP "hello" IP TCP/UDP "hello" frame IP TCP/UDP "hello" IP header: the destination address finds the HOST TCP/UDP header: the destination port finds the PROCESS only "hello" reaches the receiving process
  1. The sending process hands its data, the string "hello", to the transport layer through a socket. At this point it is just application data.
  2. The transport layer (TCP or UDP) adds its header, which holds the source and destination ports, plus a checksum.
  3. The Internet layer (IP) adds its header, which holds the source and destination IP addresses so that routers can forward the packet towards the right host.
  4. The link layer adds a frame header and sends the bits across the physical network. Each row in the middle is the same data with one more wrapper.
  5. At the receiver the package goes up, and each layer strips its own header. The link layer removes the frame header; IP checks the destination address in the IP header: yes, this is the right host.
  6. The transport layer reads the destination port in the TCP/UDP header. That port is what tells the host which process gets the data.
  7. The headers are gone, and the receiving process reads exactly the bytes that were sent: "hello".

Best effort: what IP does not promise

The Internet layer is unreliable, or "best-effort": it tries to deliver each packet but promises nothing. IP packets may be lost, duplicated, delayed or reordered. IP also checksums only its own header, not the data, so TCP and UDP add their own checksums. (A checksum is a small number computed from the bytes; the receiver recomputes it, and a mismatch reveals corruption.) Putting the check at the ends rather than in the network is the end-to-end argument from Part II at work.

sender receiver 2 lost send 1 send 2 send 3 send 4 1 arrives 4 arrives before 3 3 (delayed) 3 again: duplicate time →
All four things IP is allowed to do. Packet 2 is lost, 3 is delayed and duplicated, and 4 overtakes 3. Anything built on IP that wants reliable, ordered delivery has to repair these itself: that is precisely what TCP does (3.2).

Addresses

Hosts are identified by IP addresses. An IPv4 address is 4 bytes, written in "dotted-quad" form, one decimal number per byte, such as 128.250.25.158. An IPv6 address is 16 bytes. People use host names instead, and DNS (Part IX) maps a name to its address.

IPv4 · 4 bytes 128 250 25 158 = 128.250.25.158 IPv6 · 16 bytes each box is one byte (8 bits)
An IP address finds a computer, not a program. Nothing in these bytes says which of the many processes on that computer should get the data. That is the job of the port, the subject of 3.3.
Check yourselfA packet has reached the right computer. Which header field decides which program on that computer receives it, and which layer reads it?

The destination port in the TCP or UDP header, read by the transport layer. The IP address in the IP header only got the packet to the host; the port picks out the process.

Check yourselfWhich of these can IP do to your packets?
  1. Lose them
  2. Deliver them twice
  3. Deliver them in a different order
  4. All of the above

D. IP is best-effort: packets may be lost, duplicated, delayed or reordered. It also checks only its own header, which is why TCP and UDP carry their own checksums.

In short
  • IPC is how processes on different computers exchange messages; every later topic is built on it.
  • A protocol fixes the sequence of messages and the format of the data.
  • TCP/IP has four layers. IP gets data to the right host (best effort only); TCP/UDP get it to the right process using ports; each layer adds a header on the way down and strips it on the way up.
3.2

TCP vs UDP exam

The transport layer offers applications two protocols that make very different promises. Choosing between them, and being able to list their differences, is one of the most reliably examined skills in the subject: the 2016 exam asked for three differences outright.

Definition · TCP

TCP (Transmission Control Protocol) is "a connection-oriented protocol that provides a reliable flow of data between two computers". Its programming interface is a two-way byte stream.

Definition · UDP

UDP (User Datagram Protocol) is a connectionless protocol that sends independent packets called datagrams, "with no guarantees about arrival or order of arrival". Its interface is message passing.

Connection-oriented means the two ends must first set up a connection, an agreed two-way channel, before any data flows. Connectionless means each datagram is sent on its own, carrying its full destination address, with no set-up.

TCP: a phone call a connection is set up first, then bytes flow both ways client server …h e l l o w o r l d… one connection, both directions reliable, in order, no duplicates a stream: no message boundaries Socket, ServerSocket
TCP is a pipe. Like a phone call you dial first, then talk freely, then hang up. What you write comes out the other end complete and in order, but as one continuous stream: the receiver cannot see where one write ended and the next began.
UDP: posting letters no set-up: each datagram carries its own full address client server #1 → S:6789 #2 → S:6789 #3 → S:6789 S:6789 = server address and port may be lost, duplicated or reordered boundaries kept: one send = one receive DatagramSocket, DatagramPacket
UDP is the post. Like sending a message as several letters, each envelope is addressed separately and travels on its own. Each letter arrives whole or not at all (boundaries are kept), but some may go missing or arrive out of order, and nobody tells you.

How TCP builds reliability on top of unreliable IP

Since IP is only best-effort, TCP has to manufacture its guarantees out of extra machinery at the two ends (CDK §3.4.6). There are six mechanisms:

  • Connection set-up. The two ends agree a bidirectional channel before data flows. The routers in between know nothing about it: the connection exists only as state at the two ends.
  • Sequence numbers. Each segment carries the byte offset of its data within the stream, so the receiver can put segments back in order and drop duplicates.
  • Acknowledgements and retransmission. The receiver acknowledges ("acks") the data it has received; if no ack arrives before a timeout, the sender retransmits.
  • Flow control. Acks carry a window size: how much the sender may send before the next ack. A slow reader can therefore throttle a fast writer.
  • Receive buffering. Incoming data is held in a buffer at the receiving end until the application reads it.
  • Checksums cover both the header and the data.
TCP sender TCP receiver connection set-up: both ends create state 1 · seq=0, 100 bytes, checksum 2 · ACK 100, window 400 3 · seq=100 lost no ACK before the timeout, so retransmit 4 · seq=100 again 5 · ACK 200 byte offsets let the receiver reorder and drop duplicates checksum covers header and data
Sequence numbers, acks, timeouts and windows working together. "ACK 100" means "I have every byte before offset 100"; "window 400" means "you may send up to 400 more bytes before my next ack". The numbers are illustrative. The application sees none of this: it just writes and reads a stream.

UDP, by contrast, adds very little to IP: only ports, a length field and an optional checksum. There is no set-up and there are no acks, and a single message can be up to 64 KB. The header layouts show the difference in how much each protocol carries.

UDP src portsender's port dst portreceiver's port lengthof the datagram checksumoptional dataone whole message, up to 64 KB TCP src portsender's port dst portreceiver's port seq no.byte offset ack no.next byte expected windowflow control checksumheader + data datapart of the stream simplified: only the fields this Part mentions are shown
Shaded fields are header, white is data. UDP's header is little more than the two ports, so it adds almost nothing to IP. TCP's extra fields (sequence number, ack number, window) are the visible trace of the reliability machinery above.

The comparison table exam

Be able to reproduce most rows of this table. An exam answer that names the dimension ("Connection: …", "Reliability: …") and then states both sides is the easiest way to collect every mark.

AspectTCPUDP
ConnectionConnection-oriented: connect/accept handshake, then closeConnectionless: every datagram is independent and fully addressed
AbstractionByte stream, no message boundariesDiscrete messages, boundaries preserved
ReliabilityAcks, timeouts, retransmission. Data arrives unless the connection breaksNone. Datagrams may be lost (omission failures)
Ordering and duplicatesDelivered in sender order; duplicates discardedNo ordering; no duplicate detection
Flow controlYes (sliding window). A fast writer is blockedNone. A fast sender overruns the receiver and datagrams are dropped
OverheadHigher: state at both ends, extra messages, latencyLow: small header, no set-up, no acks
Message sizeUnlimited≤ 64 KB (often about 8 KB in practice)
MulticastNo (point-to-point)Yes (IP multicast)
Java classesSocket, ServerSocketDatagramSocket, DatagramPacket, MulticastSocket
Slide analogyA phone callSending several letters or emails, each holding part of the message
UsesHTTP, FTP, Telnet, SMTP, SSH; Skype call signallingDNS, VoIP, live streaming, online games, clock server, ping-style probes; Skype media

Why not use TCP for everything?

Because guaranteed delivery costs three overheads (CDK §4.2.3):

  1. State has to be stored at both the source and the destination (sequence numbers, buffers, timers).
  2. Extra messages have to be transmitted (the set-up handshake and the acks).
  3. The sender suffers extra latency (it must wait for the set-up before sending, and for acks).
client server 1 · request 2 · reply UDP 2 messages; no set-up; no connection state to keep
Over UDP: one message each way. If the request can simply be retried on loss (as DNS does), this is all you need.
client server SYN SYN-ACK ACK request reply (+ acks) close TCP set-up: a round trip before data extra messages and latency, and state (the TCB) kept at both ends
Over TCP: the grey messages are pure overhead for a single exchange. All three costs are visible: state at both ends, extra messages, and a round trip of latency before the request can even leave.

Choosing between them

Use TCP when…

every byte must arrive, in order: file transfer, web pages, and requests that change state (an enrolment, a bank update). The set-up cost is spread over a whole session of requests.

Use UDP when…

timeliness matters more than completeness, as with voice and video, where a late packet is useless anyway; when a short request can simply be retried, as with DNS; or when you need multicast.

Slide quirk · "Ping"

The slides list "Ping" as a UDP application, but the real ping utility uses ICMP, a different protocol. Read the slide as meaning "a simple echo or probe service".

Past exam 2016 Q4(a) · 3 marksState three differences between UDP and TCP communication.

Any three of these, each naming the dimension and both sides (this is the guide's model answer):

  • Connection. TCP is connection-oriented, so the two ends must connect and accept before any data flows. UDP is connectionless: each datagram is independent and carries its own destination.
  • Reliability. TCP uses acks, retransmission, checksums and sequence numbers, so lost packets are resent and duplicates are removed. UDP has no acks or retries, so datagrams can be lost (omission failures).
  • Ordering. TCP delivers data in sender order, whereas UDP may deliver it out of order.
  • Abstraction. TCP offers a byte stream without message boundaries, while UDP sends discrete messages of at most about 64 KB.
  • Flow control and overhead. TCP has flow control and a higher overhead in state, extra messages and latency. UDP has neither, so it gives low latency, which suits DNS and VoIP, and it also supports multicast.
Check yourselfWhich statement about UDP is false?
  1. It preserves message boundaries.
  2. It supports multicast.
  3. Its flow control stops a fast sender overrunning the receiver.
  4. A datagram may be lost without either side being told.

C is false. UDP has no flow control: a fast sender overruns the receiver and datagrams are dropped. Flow control (the sliding window) is a TCP feature. A, B and D are all true of UDP.

Check yourselfFor each, pick TCP or UDP and give the reason: (a) a live video call, (b) uploading an assignment file, (c) a DNS lookup.
  • (a) UDP. Timeliness beats completeness: a late video frame is useless, so retransmission would only add delay.
  • (b) TCP. Every byte must arrive, in order, with no duplicates.
  • (c) UDP. A short request that can simply be retried on timeout; a TCP connection set-up would cost more than the lookup itself.
Check yourself"TCP is better than UDP, so it should be used for everything." Give the textbook's three reasons why not.

Guaranteed delivery costs (1) state stored at both source and destination, (2) extra messages transmitted (set-up and acks), and (3) extra latency for the sender. Applications that can tolerate loss, or that do their own retries, avoid these costs by using UDP.

In short
  • TCP: connection-oriented, reliable, ordered byte stream with flow control and no message boundaries; costs state, messages and latency. A phone call.
  • UDP: connectionless datagrams, boundaries kept, no reliability, ordering or flow control, ≤ 64 KB, supports multicast; cheap and fast. Letters in the post.
  • TCP builds its guarantees on best-effort IP with set-up, sequence numbers, acks and retransmission, windows, receive buffers and checksums.
3.3

Ports and Sockets

The problem. An IP address only gets data as far as the right computer. But one computer runs many processes at once (a web server, a mail server, your browser), so something else has to pick out the right process. That is the job of ports. Sockets are then what those processes actually program against.

Ports exam

Definition · port

A port is a logical access point on a host, identified by a positive 16-bit integer (0–65535). TCP and UDP use ports to map incoming data to a particular process. The IP address finds the computer; the port finds the process on it.

Together the two make a transport address: the pair (IP address, port).

Analogy · a letter

Buyya compares it to posting a letter. The IP address is the house address, which gets the letter to the right building; the port is the name of the person living there, which gets it to the right reader.

incoming packets 128.250.25.158 :25 data 128.250.25.158 :80 data IP address: found the host port: finds the process HOST 128.250.25.158 TRANSPORT LAYER reads the destination port port 21 FTP server port 25 mail (SMTP) server port 80 web (HTTP) server 52311 browser (a client) port chosen by the system
One address, many processes. Both packets reach the same host because they carry its IP address; the transport layer then reads the destination port (teal) and hands each one to the process bound to that port. Servers (red) sit on agreed, well-known ports; the client (blue) gets whatever free port the system picks.

Well-known ports and port ranges

Some services have well-known ports, registered with IANA (the body that assigns Internet numbers), so that every client knows where to find them:

ftptelnetsmtphttphttpslogin
21/tcp23/tcp25/tcp80/tcp443/tcp513/tcp
a port is a 16-bit number: 0 – 65535 (ranges not to scale) 0 – 1023 well-known 1024 – 49151 registered 49152 – 65535 private usually restricted to privileged processes user-level services use ports from 1024 up
Three ranges. A program you write yourself (an assignment server, say) should pick a port of 1024 or above, because the well-known range is normally reserved for privileged (administrator) processes.

Who owns a port

The rules on ownership come from CDK §4.2.2. A port has exactly one receiving process but can have many senders; IP multicast (3.9) is the one exception. A process may use several ports, but processes cannot share a port, so a second attempt to bind one fails with BindException. A client's port is chosen by the system, whereas servers publicise their port numbers so that clients can reach them.

many senders client 1 client 2 client 3 SERVER HOST port 6789 bound server process exactly one receiving process second process bind(6789) BindException: port already in use
Many in, one out. Any number of clients may send to port 6789, but only one process can receive on it; a second process trying to bind it is refused with BindException. The only case where several processes share a port is IP multicast.

Location transparency: don't hard-code the address

Hard-coding (IP, port) into a client pins the service to one machine forever. To get location transparency (clients not needing to know where a service physically is), clients instead ask a name server or binder (Part VI, Part IX) for the service by name at runtime. This allows relocation of a service (moving it between runs and re-registering), but not migration while it is running.

name server / binder name → (IP, port) client service "X" 128.250.25.158 : 7896 0 · register("X", IP, port) 1 · lookup("X") 2 · (IP, port) 3 · connect to (IP, port) and use
One level of indirection. The client knows only the name "X". If the service is moved to another machine, it registers its new address and clients find it there next time (relocation). Violet marks middleware throughout this Part.

Sockets exam

Definition · socket

Buyya: a socket is "an endpoint of a two-way communication link between two programs running on the network". It is bound to a port, so that the transport layer can tell which application the data is for.

CDK §4.2.2 puts it in terms of IPC: interprocess communication means sending a message from a socket in one process to a socket in another. To receive, a socket must be bound to a local port and one of the host's IP addresses, and each socket uses either UDP or TCP.

Sockets come from BSD UNIX, and they are the programming interface at the transport layer. They are language-independent, so a socket program in Java can talk to one written in C. The picture is the one to carry in your head: a socket is a process's "doorway" onto the network, and its address is an IP address plus a port.

socket address = (IP address, port) CLIENT HOST 138.37.94.248 client process socket 138.37.94.248 : 52311 IP address + any free port (system picks) SERVER HOST 128.250.25.158 socket server process 128.250.25.158 : 7896 IP address + agreed (published) port message
Messages go from socket to socket. Each socket (teal) belongs to one process and is bound to one port on its host, so its full address is (IP, port). The server's port is agreed in advance so the client can find it; the client's is whatever the system hands out.

"A socket handle is treated like a file handle"

Socket I/O follows the same pattern as file I/O: you open the socket, read and write through streams, then close it. getInputStream() and getOutputStream() return ordinary Java streams, so the same wrapper classes you use for files work on sockets unchanged.

StepFileTCP socket
Opennew FileInputStream("data.txt")new Socket(host, port)
Get a streamthe stream itselfs.getInputStream(), s.getOutputStream()
Read / writeread, write, wrapped in DataInputStream etc.exactly the same wrappers
Closeclose()close()

The listen/accept model (TCP) exam

How can one TCP server talk to many clients at once, all on the same well-known port? The answer is that the server uses one socket only for listening, and gets a brand-new socket for every client it accepts:

  1. The server binds a listening socket to its well-known port and listens.
  2. The client creates a socket, to which the system assigns a port, and sends a connection request to (server host, port).
  3. The server accepts the request. This creates a new socket dedicated to that client, and all further communication with the client goes through it.
  4. The original listening socket stays open, so the server can accept other clients while it serves this one.
  5. Requests that have not yet been accepted wait in the listening socket's queue. Java's default queue length is 50, and a request that arrives when the queue is full is refused.
One listening socket, one new socket per client
SERVER HOST S server process listening socket port 1234 queue of requests not yet accepted (default 50) A B full: 50 requests waiting client A port 52311 connect socket for A port 1234 (A, 52311, S, 1234) client B port 40000 connect socket for B port 1234 (B, 40000, S, 1234) client C: refused
  1. The server creates a listening socket bound to its well-known port 1234 and waits. Its queue of pending connection requests is empty.
  2. Client A creates a socket (the system gives it port 52311) and sends a connection request to (S, 1234). Until the server accepts it, the request waits in the listening socket's queue.
  3. The server accepts. A new socket dedicated to A is created, and from now on A and the server talk only through it. It is identified by the 4-tuple (client IP, client port, server IP, server port) = (A, 52311, S, 1234).
  4. The listening socket is still open, so client B (port 40000) can connect too; its request waits in the queue while the server is busy.
  5. Another accept gives B its own new socket. Notice both new sockets use server port 1234: TCP tells them apart by the 4-tuples, which differ in the client half.
  6. If requests arrive faster than the server accepts them, the queue fills (Java's default length is 50) and a further request, here from client C, is refused.
Buyya vs the slides

Buyya's chapter says the new socket is bound to "a different port". The slides' "recent model" says it uses the same server port, and that is the correct version: TCP tells connections apart by the 4-tuple (client IP, client port, server IP, server port), so many connections can share the server's port.

Check yourselfWhat is a port and why is it needed?

A port is a 16-bit number that TCP and UDP use to map incoming data to a process. It is needed because an IP address identifies only the host. Each port has one receiver but can have many senders. Well-known ports are 0–1023 (for example FTP on 21 and HTTP on 80), and user services use ports from 1024 up.

Check yourselfDefine a socket. How does a TCP server serve many clients?

A socket is an endpoint of a two-way link between two programs. It is bound to a port, and it is programmed like a file handle.

To serve many clients, the ServerSocket listens on a well-known port, and each accept() returns a new socket for that client. The new socket has the same local port and is distinguished by the 4-tuple, while the listening socket keeps accepting. Each client socket is handed to a thread, so a blocked client does not stall the others.

Check yourselfYou start your server on port 7896, then start a second copy of it on the same machine. What happens, and why?

The second copy fails with BindException (port already in use). A port has exactly one receiving process, so two processes cannot bind the same port. (Multicast is the only exception.)

Check yourselfA server has accepted three clients. How many sockets does it hold, and which port are they on?
  1. 3 sockets on 3 different ports
  2. 3 sockets, all on the server port
  3. 4 sockets, all on the server port
  4. 1 socket shared by all clients

C. One listening socket plus one new socket per accepted client, and all of them use the server's port. The connections are distinguished by their 4-tuples (client IP, client port, server IP, server port). Option A is Buyya's older description, which the slides correct.

In short
  • A port (16-bit) picks the process on a host; (IP, port) is a transport address. One receiver per port, many senders; servers publish their ports, clients get system-chosen ones; user services use 1024 and up.
  • A socket is an endpoint of a two-way link, bound to a local port and IP address, using either UDP or TCP, and programmed like a file handle.
  • A TCP server keeps one listening socket open and gets a new socket per accepted client on the same port, told apart by the 4-tuple.
3.4

TCP Sockets in Java

Now the ideas become code. The java.net package gives you a handful of classes, and the TCP server and client each follow a short fixed recipe. This is the code the exam expects you to be able to read, explain and write.

The java.net classes

The java.net package has one class for IP addresses, two for TCP and three for UDP:

ADDRESSES TCP UDP InetAddress getByName(host) does a DNS lookup hides IPv4 vs IPv6 ServerSocket new ServerSocket(port) accept(): Socket getLocalPort() blocks returns one per client Socket new Socket(host, port) getInputStream() getOutputStream() setSoTimeout(ms) close() DatagramSocket new DatagramSocket( [port]) send(p) receive(p) blocks setSoTimeout, connect MulticastSocket joinGroup(g) leaveGroup(g) setTimeToLive(ttl) subclass of DatagramPacket to send: (buf, len, host, port) to receive: (buf, len) getData() getLength() getAddress() getPort()
Two TCP classes, three UDP classes, one for addresses. On the TCP side, a ServerSocket exists only to hand out Sockets; each Socket is one end of a connection. On the UDP side a DatagramSocket sends and receives DatagramPackets, and MulticastSocket extends it with group membership (the hollow triangle means "is a subclass of").
  • InetAddress represents an IP address and hides whether it is IPv4 or IPv6. getByName("host") does a DNS lookup and can throw UnknownHostException.
  • ServerSocket is the TCP server socket. new ServerSocket(port) binds and listens; port 0 means any free port, which you can read back with getLocalPort(). accept() blocks (the calling thread waits) until a request arrives, and then returns a Socket.
  • Socket is one end of a TCP connection. new Socket(host, port) creates the socket and connects it. Its main methods are getInputStream(), getOutputStream(), setSoTimeout() and close().
  • DatagramSocket is a UDP socket. A server constructs it with a port, and a client with none, which gives it any free port. It offers send(), a blocking receive(), setSoTimeout() and connect().
  • DatagramPacket holds one datagram: the message bytes, their length, and a host and port. There is one constructor for sending and another for receiving, and the accessors are getData(), getLength(), getAddress() and getPort().
  • MulticastSocket is a subclass of DatagramSocket that adds joinGroup(), leaveGroup() and setTimeToLive().

Stream wrappers (java.io)

A socket's streams only move raw bytes. To send typed values or lines of text, you wrap them in whichever java.io class suits your protocol, exactly as you would a file stream:

YOUR CALL WRAPPER (TYPED) RAW STREAM SOCKET out.writeUTF("hi") out.println(line) out.writeObject(o) DataOutputStream PrintWriter ObjectOutputStream OutputStream s.getOutputStream() raw bytes only Socket s → TCP → network
Wrappers turn values into bytes. Each amber wrapper converts your typed call into bytes on the one raw stream. The reading side mirrors it: DataInputStream.readUTF(), BufferedReader.readLine(), ObjectInputStream.readObject(). Both ends must use matching wrappers.
  • DataOutputStream and DataInputStream write and read primitive values (writeInt, writeUTF, …) in a machine-independent binary format, which makes them a simple external data representation (3.8).
  • For line-based text protocols, use BufferedReader.readLine() together with PrintWriter or BufferedWriter. The slides' DataInputStream.readLine() is deprecated.
  • ObjectOutputStream and ObjectInputStream send whole objects (3.8).

Be careful with writeUTF: it sends a 2-byte length followed by the UTF-8 bytes of the string, so every writeUTF must be matched by a readUTF.

out.writeUTF("hello") sends 7 bytes: 0 5 h e l l o length (2 bytes) UTF-8 bytes of the string in.readUTF() reads the length, then exactly 5 bytes → "hello" in.readLine() waits for a '\n' that is never sent → blocks, or misreads the length The two ends must agree on the framing, not just on the text.
writeUTF is length-prefixed. The two shaded bytes are a length, not text. A matching readUTF (green) uses them to know where the string ends; a mismatched readLine (red) has no idea, and either hangs or returns garbage.

Exceptions: each failure has a name

All of these are subclasses of IOException, so a single catch (IOException e) catches them all, but knowing which is which tells you what went wrong.

ExceptionWhat happened
UnknownHostExceptionA bad host name: the DNS lookup failed
ConnectException: Connection refusedNo server is listening at that (host, port), for example because the client was started before the server
BindExceptionThe port is already in use
SocketTimeoutExceptionA timeout set with setSoTimeout expired
EOFExceptionThe peer closed the stream (end of file / end of stream)

The TCP recipes exam

Server: five steps

  1. Open the server socket: new ServerSocket(PORT).
  2. Wait for a client: Socket client = server.accept().
  3. Create I/O streams from client.getInputStream() and client.getOutputStream().
  4. Communicate: read requests, write replies.
  5. Close the client socket: client.close(). The server socket stays open.

Client: four steps

  1. Create a socket with new Socket(server, port), which also connects it.
  2. Create the I/O streams.
  3. Perform I/O with the server.
  4. Close the socket.

The client

The client below follows the four steps, and its comments mark each one. It sends the string "hello" and prints what comes back.

// TCPClient.java - send a string, print the reply
import java.net.*;
import java.io.*;

public class TCPClient {
    public static void main(String[] args) {
        try (Socket s = new Socket("localhost", 7896)) {                  // 1. connect
            DataInputStream in = new DataInputStream(s.getInputStream());     // 2. streams
            DataOutputStream out = new DataOutputStream(s.getOutputStream());
            out.writeUTF("hello");                                       // 3. send
            System.out.println("Received: " + in.readUTF());             //    receive
        } catch (UnknownHostException e) {
            System.out.println("Unknown host: " + e.getMessage());
        } catch (IOException e) {                    // e.g. ConnectException if server not up
            System.out.println("IO: " + e.getMessage());
        }                                            // 4. try-with-resources closes the socket
    }
}
LineWhat it does and why
import java.net.*; java.io.*;Sockets live in java.net; streams and IOException in java.io.
try (Socket s = new Socket("localhost", 7896))Step 1. Creates the socket and connects to port 7896 on this machine; the constructor returns only once the connection is set up. Declaring it in try (…) ("try-with-resources") means Java closes it automatically at the end, even on an exception.
new DataInputStream(s.getInputStream())
new DataOutputStream(s.getOutputStream())
Step 2. Wraps the raw byte streams so we can read and write typed values.
out.writeUTF("hello")Step 3. Sends the 2-byte length and the UTF-8 bytes of "hello".
in.readUTF()Blocks until the server's reply arrives, then returns it as a string, which is printed.
catch (UnknownHostException e)The host name could not be resolved. This catch must come before the IOException one, because it is a subclass.
catch (IOException e)Any other network failure, for example ConnectException if the server is not running.
closing brace of tryStep 4. The socket is closed here automatically.

The server, and why it uses threads

A server must serve many clients. The slides' recipe for that is a while(true) loop that accepts a client and then creates a thread, passing it the client socket as a parameter. (A thread is an independent line of execution inside a process; Part IV covers them fully.) The thread creates the streams, serves the client, and ends when it is done. This design is called thread-per-connection (CDK Fig. 4.6).

The contrast is an iterative server, such as the slides' SimpleServerLoop, which does the same work in the main thread. While it is blocked serving one slow client, it cannot accept() anyone else.

A B C ITERATIVE SERVER main thread: serving A accept queue B C waiting: nobody calls accept()
Iterative: one at a time. While the main thread is blocked in A's readUTF(), B and C wait in the queue, however quick their requests are.
A B C THREAD-PER-CONNECTION main: accept() loop thread for A thread for B thread for C creates
Thread-per-connection: all at once. The main thread only accepts; each client gets its own thread, so one client blocking in a read stalls nobody else.
// TCPServer.java - echo server, one thread per connection
import java.net.*;
import java.io.*;

public class TCPServer {
    public static void main(String[] args) throws IOException {
        ServerSocket listenSocket = new ServerSocket(7896);       // 1. open server socket
        while (true) {
            Socket clientSocket = listenSocket.accept();          // 2. wait for a client
            new Thread(new Connection(clientSocket)).start();     // hand it to a worker thread
        }
    }
}

class Connection implements Runnable {
    private final Socket socket;
    Connection(Socket socket) { this.socket = socket; }

    public void run() {
        try (Socket s = socket;                                    // 5. closed automatically
             DataInputStream in = new DataInputStream(s.getInputStream());      // 3. streams
             DataOutputStream out = new DataOutputStream(s.getOutputStream())) {
            while (true) {
                String data = in.readUTF();    // 4. blocks THIS thread only
                out.writeUTF(data);            //    echo
            }
        } catch (EOFException e) {             // client closed its end
            System.out.println("Client left");
        } catch (IOException e) {
            System.out.println("IO: " + e.getMessage());
        }
    }
}
LineWhat it does and why
new ServerSocket(7896)Step 1. Binds the listening socket to port 7896 and starts listening. Throws BindException if the port is taken.
while (true)A server runs forever, accepting one client after another.
listenSocket.accept()Step 2. Blocks the main thread until a client connects, then returns a new Socket for that client. The listening socket stays open.
new Thread(new Connection(clientSocket)).start()Hands the client socket to a fresh thread and starts it; the main thread immediately loops back to accept().
class Connection implements RunnableThe work one thread does. Runnable means it has a run() method the thread executes. The socket arrives through the constructor.
try (Socket s = socket; DataInputStream in …; DataOutputStream out …)Steps 3 and 5. Creates the streams, and guarantees that the socket and streams are closed when the thread finishes, however it finishes.
in.readUTF()Step 4. Blocks this thread only until the client sends a string. The other clients' threads carry on.
out.writeUTF(data)Echoes the string back.
catch (EOFException e)The client closed its end, so readUTF hit end of stream: the normal way this loop ends.
catch (IOException e)Any other failure, such as a broken connection.

Run the two programs against each other and this is the order in which the calls happen:

TCPClient meets TCPServer, call by call
TCPClient (main) ServerSocket :7896 new ServerSocket(7896) accept() blocks… 1 · new Socket("localhost", 7896) 2 · accepted: constructor returns 3 · accept() returns Connection thread new Thread(…).start(), then loops back to accept() creates streams; readUTF() blocks… 4 · out.writeUTF("hello") readUTF() returns "hello" 5 · out.writeUTF(data): echo in.readUTF() returns; prints "Received: hello" 6 · close(): end of stream readUTF() throws EOFException: "Client left", close()
  1. The server starts first: new ServerSocket(7896) binds and listens, and accept() blocks the main thread until a client turns up. (If the client were started first, its connect would fail with ConnectException.)
  2. The client's new Socket("localhost", 7896) sends a connection request to the listening socket.
  3. The request is accepted, the connection is set up, and the client's Socket constructor returns: the client is connected and creates its streams.
  4. On the server, accept() returns a new Socket, which the main thread hands to a new Connection thread before looping straight back to accept() for the next client. The thread creates its streams and blocks in readUTF().
  5. The client calls out.writeUTF("hello"). The bytes arrive on the per-client socket, and the thread's readUTF() returns "hello".
  6. The thread echoes the string with writeUTF; the client's readUTF(), which was blocked, returns and it prints Received: hello.
  7. The client's try-with-resources closes its socket. On the server side the thread's next readUTF() finds end of stream and throws EOFException; it prints "Client left" and its own try-with-resources closes its socket. The listening socket is untouched.

Message framing over TCP exam

The problem. TCP delivers a byte stream with no message boundaries. TCP itself decides how to cut the data into segments, and a read returns whatever bytes have arrived so far. So one write may arrive split over several reads, which is called a partial read, and, conversely, several writes may arrive together in one read.

writer calls write("ABC") write("DEF") TCP byte stream ABC DEF reader gets read → "AB" read → "CDEF" one write ≠ one read • a write may be split over several reads (a partial read: "AB", then "C…") • several writes may come back in one read ("…C" and "DEF" together)
The stream forgets where writes ended. The dotted lines are the write boundary (top) and the read boundary (bottom); they don't line up. If "ABC" and "DEF" were two messages, the receiver has no way to tell from the bytes alone.

The fix. The application protocol must frame each message so that the receiver knows where it ends. There are three ways:

Delimiter A B C \n D E F \n end each message with '\n'; buffer until you see it readLine(); e.g. one JSON object per line (Assignment 1) Length prefix 3 A B C 3 D E F send the byte count, then the bytes writeUTF/readUTF; writeInt + readFully Fixed size A B C D E F every message has the same agreed size (here 5 bytes; grey = padding)
Three ways to mark where a message ends. With a delimiter (gold) the message itself must not contain the delimiter; JSON meets that requirement because it escapes newlines inside strings. With a length prefix (shaded) the receiver reads exactly that many bytes next.

What goes wrong without framing. A message that is cut in two fails to parse, or a reader blocks forever waiting for data that the writer thinks it has already sent. This is the "matching of data items" issue of 3.7. The snippet shows the delimiter approach, with one JSON object per line.

// Line-framed JSON (also import java.nio.charset.StandardCharsets)
BufferedReader in = new BufferedReader(
        new InputStreamReader(s.getInputStream(), StandardCharsets.UTF_8));
PrintWriter out = new PrintWriter(
        new OutputStreamWriter(s.getOutputStream(), StandardCharsets.UTF_8), true); // autoflush
out.println("{\"op\": \"QUERY\", \"subjectCode\": \"COMP90015\"}"); // one object + '\n'
String reply = in.readLine();  // collects partial reads until '\n'; null means peer closed
  • InputStreamReader(…, UTF_8) turns bytes into characters using an explicit encoding, and BufferedReader adds readLine().
  • PrintWriter(…, true): the true turns on autoflush, so every println is sent immediately.
  • out.println(…) writes one JSON object followed by the '\n' delimiter.
  • in.readLine() keeps collecting partial reads until it sees '\n', then returns the whole line; it returns null when the peer has closed the connection.
The flush trap

A buffered writer holds data until it is flushed. Forgetting to call flush(), or to enable autoflush as the snippet does, leaves the peer blocked in readLine() forever, even though your code "sent" the message.

Check yourselfWhich line creates a TCP server?
  1. new Socket(host, 7896)
  2. new ServerSocket(7896)
  3. new DatagramSocket()
  4. server.accept()

B. new ServerSocket(port) binds and listens. new Socket(host, port) always creates a client socket and connects it (a common pitfall). accept() is called on an existing server socket, and DatagramSocket is UDP.

Check yourselfA client calls out.writeUTF("hi") and the server reads with BufferedReader.readLine(). What happens?

The server receives a 2-byte length followed by "hi", with no newline, so readLine() blocks waiting for a '\n' that never comes (or, later, returns a line with garbage length bytes in it). Every writeUTF must be matched by a readUTF: the two ends must agree on the framing.

Check yourselfWhy does the server in TCPServer hand each client socket to a new thread rather than serving it in main?

Because readUTF() blocks. In an iterative server, while main is blocked waiting for one slow client it cannot call accept(), so every other client waits. With thread-per-connection, a read blocks only that client's thread; main goes straight back to accept().

Check yourselfA client sends two JSON requests with two separate write calls. The server does one read and gets both, run together. Is TCP broken? What should the protocol do?

No: TCP is a byte stream with no message boundaries, so several writes may arrive in one read (and one write may be split over several). The application must frame its messages: a delimiter such as one JSON object per line read with readLine, a length prefix, or fixed-size messages.

In short
  • Server: new ServerSocket(port) → accept() (blocks, returns a new Socket) → streams → read/write → close the client socket. Client: new Socket(host, port) (connects) → streams → I/O → close.
  • Wrap the raw streams (DataInput/OutputStream, BufferedReader/PrintWriter, object streams) and match every write with the corresponding read.
  • Serve many clients with a thread per connection. TCP has no message boundaries, so frame messages with a delimiter, a length prefix or a fixed size, and flush.
3.5

UDP Sockets in Java

With UDP there is no connection to set up, so the code deals only with sockets and packets. That makes it shorter than the TCP code, but it also means the program itself has to cope with whatever the network does: nothing tells you a datagram went missing.

A process creates a DatagramSocket. A server binds it to its agreed port, while a client lets the system pick any free port. To send, you build a DatagramPacket(bytes, length, address, port) and call send(): no connection is needed, because every packet carries its own destination. To receive, you pass in an empty DatagramPacket(buffer, buffer.length), and receive() fills in the data, its length and the sender's address and port. That last part is how the receiver knows where to send a reply.

to send (m, m.length, host, 6789) datah e l l o length5 addresshost port6789 to receive (buffer, buffer.length) data1000 empty bytes length1000 addressnot set portnot set socket.receive(p) fills in after receive() datahello + stale bytes length5 addresssender's IP portsender's port
One class, two uses. A packet you send carries its destination; a packet you receive into starts empty, and receive() fills in the length and the sender's address and port (gold). Reply by sending to exactly that address and port. Only the first getLength() bytes of the buffer are the new message; the rest is whatever was there before.

The client sends one datagram and waits for an answer; the server echoes each datagram back to whoever sent it.

// UDPClient.java - send one datagram and wait up to 2 s for the reply
import java.net.*;
import java.io.*;

public class UDPClient {
    public static void main(String[] args) {                 // args: message, server host
        try (DatagramSocket socket = new DatagramSocket()) {   // any free local port
            byte[] m = args[0].getBytes();
            InetAddress host = InetAddress.getByName(args[1]);
            socket.send(new DatagramPacket(m, m.length, host, 6789));
            DatagramPacket reply = new DatagramPacket(new byte[1000], 1000);
            socket.setSoTimeout(2000);                         // don't block forever
            socket.receive(reply);
            System.out.println(new String(reply.getData(), 0, reply.getLength()));
        } catch (SocketTimeoutException e) {
            System.out.println("Timeout: request/reply lost or server down");
        } catch (IOException e) {
            System.out.println("IO: " + e.getMessage());
        }
    }
}
LineWhat it does and why
new DatagramSocket()A UDP socket on any free local port: a client doesn't need a fixed port, because the server will learn it from each datagram. In try-with-resources, so it is closed at the end.
args[0].getBytes()Turns the message string into bytes; a datagram carries bytes, not strings.
InetAddress.getByName(args[1])Looks up the server's IP address from its name (DNS); may throw UnknownHostException.
socket.send(new DatagramPacket(m, m.length, host, 6789))Builds a sending packet addressed to port 6789 on the server and sends it. send returns at once: there is no connection and no acknowledgement.
new DatagramPacket(new byte[1000], 1000)An empty receiving packet with room for 1000 bytes.
socket.setSoTimeout(2000)Limits the next receive to 2 seconds. Without it, a lost request or reply would leave the client blocked forever.
socket.receive(reply)Blocks until a datagram arrives (or the timeout fires), then fills in reply.
new String(reply.getData(), 0, reply.getLength())Converts only the bytes that actually arrived (getLength()), not the whole 1000-byte buffer.
catch (SocketTimeoutException e)No reply within 2 s: the request or the reply was lost, or the server is down. UDP cannot tell you which.
// UDPServer.java - echo each datagram back to its sender
import java.net.*;
import java.io.*;

public class UDPServer {
    public static void main(String[] args) {
        try (DatagramSocket socket = new DatagramSocket(6789)) {   // agreed server port
            byte[] buffer = new byte[1000];
            while (true) {
                DatagramPacket request = new DatagramPacket(buffer, buffer.length);
                socket.receive(request);                           // from ANY sender
                socket.send(new DatagramPacket(request.getData(), request.getLength(),
                        request.getAddress(), request.getPort()));  // reply to sender
            }
        } catch (IOException e) {
            System.out.println("IO: " + e.getMessage());
        }
    }
}
LineWhat it does and why
new DatagramSocket(6789)Binds the server's socket to the agreed port 6789, so clients know where to send.
byte[] buffer = new byte[1000]One receive buffer, reused for every datagram. A longer datagram would be silently truncated.
new DatagramPacket(buffer, buffer.length)An empty receiving packet over that buffer.
socket.receive(request)Blocks until a datagram arrives from any sender, then fills in the data, length, and the sender's address and port.
new DatagramPacket(request.getData(), request.getLength(), request.getAddress(), request.getPort())Builds the reply: the same bytes, addressed back to whoever sent the request.
socket.send(…)Sends the echo; then the loop goes back to receive for the next datagram, from whichever client.
UDPClient meets UDPServer, call by call
UDPClient UDPServer new DatagramSocket(): any free port new DatagramSocket(6789) receive(request) blocks… 1 · send(DatagramPacket(m, m.length, host, 6789)) send() returns at once receive() returns: data, length, client's IP and port setSoTimeout(2000); receive(reply) blocks ≤ 2 s 2 · send(reply to getAddress(), getPort()) loops: receive() again receive() returns; prints new String(data, 0, getLength()) alt: a datagram is lost 1 · send(request) lost: nobody is told 2 s pass with no reply: SocketTimeoutException prints "Timeout: request/reply lost or server down" still blocked in receive(); never knew a request was sent
  1. The server binds a DatagramSocket to port 6789 and blocks in receive. The client creates a DatagramSocket on any free port. No connection is made: neither side knows about the other yet.
  2. The client builds a packet addressed to (host, 6789) and calls send(). Send is non-blocking: it returns as soon as UDP has the datagram.
  3. The server's receive() returns, and the request packet now holds the data, its length, and the client's IP address and port.
  4. The client sets a 2-second timeout and blocks in receive(reply).
  5. The server replies to request.getAddress(), request.getPort(), the address it just learned, and loops back to receive for the next datagram from anyone.
  6. The client's receive returns, and it prints only the first getLength() bytes of the buffer.
  7. If the request or the reply is lost, nobody is told. The client's timeout fires after 2 s with SocketTimeoutException; without the timeout it would block forever. The client cannot tell whether the request, the reply or the server was the problem.

Three pitfalls in the slide and textbook versions

  • Use m.length, which counts bytes, rather than the string's length(), which counts characters. The two differ for non-ASCII text (an accented letter is two bytes in UTF-8).
  • Print only getLength() bytes of the buffer, because otherwise stale buffer contents are printed too.
  • A message larger than the buffer is silently truncated:
sent 1500-byte datagram received buffer: new byte[1000] 500 bytes dropped no exception, no warning: the end of the message is simply gone
Truncation is silent. The receiver supplies the buffer, so it must be big enough for the largest message the protocol allows; otherwise the excess is discarded without any error.
Check yourselfHow does the UDP server know where to send its reply, when it never connected to the client?

receive() fills in the sender's IP address and port in the request packet. The server reads them with request.getAddress() and request.getPort() and builds its reply packet addressed there.

Check yourselfWhy does the UDP client call setSoTimeout but the UDP server doesn't?

A server waiting for requests is happy to wait forever: that is its job. A client waiting for a reply must not, because the request or reply may have been lost or the server may have crashed, and UDP never reports either. The timeout turns "wait forever" into a SocketTimeoutException the client can handle (for example by retrying).

In short
  • UDP code is just DatagramSocket + DatagramPacket: no connection. A server binds its agreed port; a client takes any free port.
  • Send packets carry their destination; receive packets are filled in with the data, its length and the sender's address and port, which is how the reply is addressed.
  • Use byte lengths, print only getLength() bytes, size the buffer for the largest message, and give the client a timeout.
3.6

Characteristics of IPC exam

This section steps back from code to the general vocabulary CDK (§4.2.1) uses to describe any message-passing IPC. The same words (synchronous, blocking, reliable, ordered) come back in RPC, group communication and every later topic, so they are worth getting exactly right.

Message passing uses two operations, send and receive, defined in terms of a message (a sequence of bytes) and a destination. Each destination has a queue: senders add messages to it, and the receiver removes them.

sending process DESTINATION = (IP ADDRESS, PORT) send(m, dest) queue m3 m2 m1 senders add at one end… …the receiver removes from the other receiving process receive()
A queue decouples the two. Whether send or receive has to wait for the other side is exactly the synchronous/asynchronous distinction below.

Synchronous vs asynchronous; blocking vs non-blocking

An operation is blocking if the calling process (or thread) is suspended until something happens; non-blocking if it returns at once. The main distinction is between synchronous and asynchronous communication, and the table shows what each means for the two operations. Notice that only the asynchronous send is non-blocking, while receive is usually blocking either way.

sendreceive
SynchronousBlocking: waits until the matching receive is issuedBlocking: waits until a message arrives
AsynchronousNon-blocking: returns once the message is copied to a local buffer; transmission continues in parallelBlocking (usual), or non-blocking: a buffer is filled in the background and the program is told by polling or interrupt
Synchronous sender receiver send receive message taken send returns gold = blocked: both sides wait for each other
Synchronous: both block. The sender cannot continue until the matching receive has been issued, so the two processes synchronise on every message.
Asynchronous sender receiver send: copied keeps working (green) receive message arrives non-blocking send; receive usually blocks
Asynchronous: the sender doesn't wait. Send returns once the message is in a local buffer and transmission continues in parallel. Receive may still block (as here), or be non-blocking with notification by polling or interrupt.
Why blocking receive is fine in Java

With multiple threads, one thread can block in receive while the others keep working, and blocking code is much simpler to write and read. Non-blocking receive looks more efficient, but it forces the program to handle messages outside its normal flow of control (in a callback or interrupt), so today's systems generally don't offer it.

In practice: Java's UDP has a non-blocking send and a blocking receive. With TCP, a read blocks until data arrives, and a write can block under flow control (when the receiver's buffer is full).

Destinations, reliability and ordering

Message destinations are (IP address, local port) pairs, with one receiver per port (3.3). The other two characteristics describe what the service promises about delivery.

Validity

Messages are guaranteed to be delivered despite a "reasonable" number of packets being dropped or lost. A service is unreliable if delivery can fail after even one lost packet.

Integrity

Messages arrive uncorrupted and without duplication: exactly the bytes that were sent, exactly once.

Ordering

Some applications need sender-order delivery (the order the messages were sent), and they treat out-of-order delivery as a failure.

Reliability, in CDK's sense, is validity plus integrity (the failure model of Part II). Keep these three words: the failure models in 3.7 are stated in exactly these terms.

Check yourselfSynchronous vs asynchronous communication: what's the difference, and why is blocking receive acceptable?

In synchronous communication, send and receive both block, so the processes synchronise on every message. In asynchronous communication, send returns once it has copied the message to a local buffer, and receive may block or not; a non-blocking receive is notified by polling or interrupt.

Blocking receive is acceptable because, with threads, one thread can block while the others run. Blocking is also simpler, which is why non-blocking receive is rarely provided.

Check yourselfWhich operation is non-blocking?
  1. Synchronous send
  2. Synchronous receive
  3. Asynchronous send
  4. Java's DatagramSocket.receive()

C. Asynchronous send returns once the message is copied to a local buffer. Synchronous send and receive both block, and Java's UDP receive() blocks (until a datagram arrives or a timeout fires).

Check yourselfA message arrives intact but twice. Which reliability property is violated: validity or integrity?

Integrity, which requires messages to arrive uncorrupted and without duplication. Validity is about messages being delivered at all despite lost packets.

In short
  • Send puts a message on the destination's queue; receive takes it off. Destinations are (IP, port).
  • Synchronous: blocking send and blocking receive. Asynchronous: non-blocking send; receive usually blocking (or non-blocking with polling/interrupt). Java UDP = non-blocking send, blocking receive.
  • Reliability = validity (delivered despite reasonable loss) + integrity (uncorrupted, no duplicates); some applications also need sender ordering.
3.7

UDP and TCP: Issues and Failure Models exam

CDK now looks at each protocol in turn through the lens of 3.6: what issues a programmer must handle, and what can go wrong (its failure model, the precise list of failures it can suffer). These lists are frequently examined, and the TCP one contains the subject's favourite trick question: "is TCP reliable?"

UDP datagram communication (CDK §4.2.3)

A datagram is sent without acknowledgements or retries. There are four issues to know when using UDP:

Issue 1

Message size

The receiver supplies a fixed-size array, and longer messages are truncated. IP allows up to 216 bytes including headers, but most systems limit messages to about 8 KB, so larger data must be fragmented by the application.
Issue 2

Blocking

Send is non-blocking (it returns once UDP/IP has the message); receive is blocking. An arriving message is queued at the socket bound to its destination port, and if no socket is bound there, it is discarded. To do other work while waiting, use separate threads.
Issue 3

Timeouts

Waiting forever suits a server waiting for requests. A client waiting for a reply needs setSoTimeout(), because the sender may have crashed or the message may be lost. The interval should be large compared with the transmission time.
Issue 4

Receive from any

receive accepts a message from any origin and reports who sent it. connect() restricts the socket to a single peer.

UDP's failure model

sender receiver checksum error no buffer space send 1 send 2 send 3 send 4 4 arrives then 3 omission failures (1 and 2) ordering failure (4 before 3)
What UDP can do to your messages. Omission failures (red): datagrams dropped because of checksum errors or lack of buffer space at the source or destination. Ordering failures (gold): delivery out of sender order. Corruption is rare thanks to the checksum, but nothing detects duplicates.
  • Integrity: UDP's checksum makes corruption negligible, but there is no duplicate detection.
  • Omission failures: messages are dropped because of checksum errors or a lack of buffer space at the source or destination.
  • Ordering failures: messages can be delivered out of sender order.

Applications therefore add their own checks: acknowledgements, retransmission and duplicate filtering turn UDP into a reliable request-reply protocol, which is exactly what Part VI builds. Uses: UDP suits DNS and VoIP, where occasional loss is acceptable, and more generally any application that wants to avoid the three overheads of guaranteed delivery.

Check yourselfDescribe UDP's failure model and how to make it reliable.

UDP suffers omission failures, caused by checksum errors or a lack of buffer space, and ordering failures. Its checksum gives integrity, but only against corruption. To make UDP reliable, you add acks, timeouts with retransmission, and sequence or request IDs that let the receiver filter duplicates and reorder messages. That is what a request-reply protocol does (Part VI).

TCP stream communication (CDK §4.2.4)

TCP takes the opposite approach: it presents the application with a stream and hides the awkward properties of the network underneath. There are five network characteristics the stream abstraction hides:

WHAT THE NETWORK DOES WHAT THE TCP STREAM SHOWS THE APPLICATION 1 · Message sizespackets have a limited size write and read any amount; TCP decides how tosplit it into packets; flush forces sending 2 · Lost messagespackets get dropped acknowledgements and retransmission, with asliding window to reduce the number of acks 3 · Flow controla fast writer can swamp a slow reader a writer that is too fast for its reader is blocked 4 · Duplication and orderingpackets duplicated or reordered packet identifiers let the receiver rejectduplicates and put packets back in order 5 · Message destinationsevery packet needs an address after connect/accept the processes just readand write: no per-message addresses
Red is the network, green is the illusion. Each of the five awkward properties on the left is hidden by one TCP mechanism on the right. The fifth has a price: connection set-up is costly for a single request-reply exchange, which is why request-reply protocols often use UDP instead (Part VI).

Roles, streams and closing

The client creates a socket and connects; the server's listening socket holds a queue of requests and accepts them. After set-up, the two can act as peers: each socket has an input stream and an output stream. Closing a socket means "I will write no more": data already buffered is still delivered, and once the reader has consumed it, further reads report end of stream (EOFException, -1, or null, depending on the read method). Using a broken stream gives an IOException.

writer reader write a write b close() "I will write no more" read → a read → b read → end of stream EOFException, -1 or null buffered data still delivered
Close is a polite goodbye, not a hang-up. Everything written before close() still arrives; only after it has all been read does the reader see end of stream. That is the signal the echo server in 3.4 catches as EOFException.

Three issues when using TCP streams

  • Matching of data items. The two sides must agree on the content and order of what is sent. If one writes an int then a double, the other must read an int then a double; otherwise the data is misinterpreted or the reader blocks. Framing (3.4) is part of this agreement.
  • Blocking. Reads block when no data is queued, and writes block under flow control.
  • Threads. A server typically creates one thread per accepted connection, so that blocking on one client doesn't delay the others. Without threads, UNIX select can test which streams have input ready.
Reads match writes writeInt(7) writeDouble(2.5) 4 bytes 8 bytes readInt() → 7 readDouble() → 2.5 same types, same order, same sizes
Good: the reader asks for an int then a double, exactly what was written.
Reads in the wrong order writeInt(7) writeDouble(2.5) 4 bytes 8 bytes readDouble() → ??? readInt() → ??? the bytes are fine; their meaning is wrong
Bad: TCP delivered every byte correctly, yet both values are garbage, because the stream carries no types. Had the reader asked for more bytes than were written, it would block instead.

TCP's failure model: is TCP reliable?

TCP protects integrity with checksums and sequence numbers, and validity with timeouts and retransmission. Even so, TCP is still not fully reliable. With excessive loss, a severed network or heavy congestion, TCP eventually declares the connection broken. When that happens, the processes cannot distinguish a network failure from a crash of the remote process, and they cannot tell whether their recent messages were received.

Case 1: the network fails client serverstill running client sees: IOException, connection broken "Was my last request received? Is the server alive?"
A partition. The server is fine but unreachable.
Case 2: the server crashes client servercrashed client sees: IOException, connection broken "Was my last request received? Is the server alive?"
A crash. The network is fine but nobody is listening.

The two gold boxes are identical, and that is the point: from the client's side the two cases look exactly the same, and in neither can it know whether its last messages got through. Uses: TCP carries HTTP, FTP, Telnet and SMTP, each on a reserved port.

How this is examined

"Is TCP reliable?" wants a two-sided answer: yes, it masks packet loss (checksums and sequence numbers for integrity, retransmission for validity); but no, not in all circumstances, because under severe loss or a partition it declares the connection broken, and then the processes can't tell a network failure from a peer crash, nor whether recent messages arrived. "TCP is fully reliable" is a stated pitfall.

Check yourselfWhich characteristics of the network does the TCP stream abstraction hide?

Five:

  1. Message sizes: the application can write and read any amount.
  2. Lost messages: dealt with by acks and retransmission.
  3. Flow control: a fast writer is blocked.
  4. Duplication and ordering: handled with sequence numbers (packet identifiers).
  5. Message destinations: only needed at connect time.
Check yourselfIs TCP reliable?

TCP masks packet loss: checksums and sequence numbers give integrity, and retransmission gives validity. But with severe loss or a partition it declares the connection broken, and the processes then cannot tell a network failure from a crash of the peer, nor whether their recent messages arrived. So TCP does not guarantee delivery in all circumstances.

Check yourselfA UDP datagram arrives at a host, but no socket is bound to its destination port. What happens?
  1. It waits in a queue until a socket binds the port
  2. It is discarded
  3. The sender gets an exception
  4. It is delivered to any socket on the host

B. An arriving datagram is queued at the socket bound to its destination port; if there is none, the message is discarded. UDP sends no notification back, so the sender never finds out.

In short
  • UDP issues: message size (truncation, about 8 KB), non-blocking send / blocking receive (unbound port → discarded), timeouts, receive from any. Failure model: omission and ordering failures; checksum for corruption but no duplicate detection.
  • TCP hides message sizes, loss, flow control, duplication/ordering and destinations. Issues: matching data items, blocking, threads.
  • TCP is not fully reliable: a broken connection can't be told apart from a peer crash, and recent messages may or may not have arrived.
3.8

Marshalling and External Data Representation exam

The problem. Inside a program, data lives in structures: records, arrays, objects pointing at other objects. A network carries only a flat sequence of bytes. So before sending, the data must be flattened into bytes, and on arrival it must be rebuilt. The complication is that machines differ in how they lay data out in memory:

  • byte order: big-endian machines store the most significant byte of a number first, little-endian machines the least significant byte first;
  • floating-point formats;
  • character codes: ASCII (one byte per character) versus Unicode.
1984 = 0x000007C0 (4 bytes) byte 0byte 1byte 2byte 3 big-endian most significant byte first 00 00 07 C0 little-endian least significant byte first C0 07 00 00 Copy the bytes across unchanged… a little-endian machine reading the big-endian bytes as its own gets 0xC0070000 = 3,221,684,224 Same bytes, different machines, different numbers: that is why an agreed representation is needed.
Byte order is invisible until data crosses machines. The value 1984 needs four bytes, and the two kinds of machine store them in opposite orders. Sending raw memory from one to the other silently turns 1984 into over three billion.

There are two ways to cope with these differences:

1 · Convert to an agreed external format sender agreed formate.g. Sun XDR: always big-endian receiver converts converts 2 · Send in the sender's format, plus a flag saying which sender flag:big-end. data in thesender's order receiver no conversion converts only if its order differs (e.g. CORBA CDR)
Always convert, or convert only when needed. Approach 1 costs a conversion at both ends even between identical machines; approach 2 skips it when sender and receiver match, at the price of a flag in every message.
Definitions
  • An external data representation is "an agreed standard for the representation of data structures and primitive values".
  • Marshalling is assembling a collection of data items into a form suitable for transmission in a message: translating it into the external representation.
  • Unmarshalling is the reverse: disassembling it on arrival into an equivalent collection of data items.

Marshalling is usually done by middleware, using generated or generic code, because doing it by hand is error-prone.

The table compares the four representations covered below. The rows on type information and marshalling code are the ones that separate CDR from Java serialization most sharply.

CORBA CDRJava serializationXMLJSON
FormBinaryBinaryTextText
Type info carriedNone (types known from IDL)Full: class name, version, field names and typesTags; meaning given by namespaces and schemasField names plus basic types
LanguagesMany, via IDLJava onlyAnyAny
Marshalling codeGenerated from IDLGeneric, via reflectionParser librariesParser libraries
SizeCompactFairly compactVerboseLighter than XML
Used inCORBAJava RMI, object streamsSOAP web services, config filesWeb/REST APIs, Assignment 1

To make the comparison concrete, the rest of this section encodes the same record in each format: a person called Smith, from London, born in 1984.

CORBA Common Data Representation (CDR)

CORBA is a multi-language middleware; IDL (Interface Definition Language) is the language-neutral notation in which both sides declare their data types. CDR has 15 primitive types, including short (16-bit), long (32-bit), their unsigned variants, float, double, char, boolean, octet (a raw byte) and any. Two rules govern how values are laid out:

  • Byte order: values are sent in the sender's byte order, which is flagged in the message, and the receiver converts only if its own order differs (approach 2 above).
  • Alignment: a primitive of n bytes starts at an index that is a multiple of n.

Constructed types are built from the primitives:

TypeSent as
string, sequencea length, followed by the elements
arraythe elements only (its length is fixed and known)
structits fields in declaration order
enuman unsigned long
uniona type tag, followed by the chosen member

No type information is sent. Both sides know the types from the IDL definition, and the IDL compiler generates the marshalling code. (Sun XDR, used by NFS, works similarly but always uses big-endian.) Step through the marshalling of struct Person {string name; string place; unsigned long year;} holding {"Smith", "London", 1984}, laid out 4 bytes per row:

Marshalling a Person in CORBA CDR, field by field
IDL (BOTH SIDES HAVE IT) struct Person { string name; string place; unsigned long year; }; value: {"Smith", "London", 1984} INDEX 4 BYTES PER ROW NOTES 0–3 4–7 8–11 12–15 16–19 20–23 24–27 5 length of "Smith" Smit "Smit" h000 "h" + padding 6 length of "London" Lond "Lond" on00 "on" + padding 1984 unsigned long 28 bytes; no field names, no types: the IDL supplies them
  1. Both sides already hold the IDL definition of Person, so the message needs to carry only values, in declaration order. Each row is 4 bytes.
  2. The first field, name, is a string, and a string is sent as its length first: the number 5, as a 4-byte unsigned long (bytes 0–3).
  3. Then the characters themselves, one byte each: "Smit" fills bytes 4–7.
  4. The last character "h" goes in byte 8, and the row is padded with zeros to the next 4-byte boundary, so that the next 4-byte value starts at an index that is a multiple of 4 (the alignment rule).
  5. The second field, place: its length 6 in bytes 12–15.
  6. "Lond" in bytes 16–19…
  7. …and "on" plus two bytes of padding in bytes 20–23.
  8. The last field, year, is an unsigned long: 1984 in bytes 24–27, in the sender's byte order (flagged elsewhere in the message).
  9. Total: 28 bytes, and nothing in them says "name", "string" or "year". The receiver's IDL-generated code unmarshals by reading the same fields in the same order.
0-3   5        length of "Smith"
4-7   "Smit"
8-11  "h___"   padded with zeros to a 4-byte boundary
12-15 6        length of "London"
16-19 "Lond"
20-23 "on__"
24-27 1984     unsigned long

Java object serialization

Java takes the opposite approach to CDR and sends type information along with the data. Serialization flattens an object, or a connected set of objects, for storage or transmission (for example as RMI arguments, Part VI), and deserialization restores them. A class allows this by declaring implements Serializable, a marker interface: one with no methods, which only labels the class as serializable.

The receiver is assumed to have no prior knowledge of the types, so the stream carries class information: the class name and a version number (serialVersionUID, or a hash of the class definition). The receiver uses it to check that it has the correct version of the class.

Person 8-byte version number h0 3 int year java.lang.String name java.lang.String place 1984 5 Smith 6 London h1 class name, version number, handle number of fields, then the type and name of each values of the fields simplified, after CDK Fig. 4.9: the real stream also contains type markers
The data describes itself. Compare with the CDR rows above: the same three values (white) now travel with the class name, version and every field's type and name (shaded). That is why any Java receiver can rebuild the object without having been told its layout in advance, and why the format is tied to Java. The gold handles are explained next.

The whole object graph is serialized. If the object refers to other objects, those are serialized too. References are written as handles (small numbers standing for an object already in the stream), and each object and class is written only once; any later occurrence just uses the handle. This is what preserves shared references and cycles.

IN MEMORY p1: Person p2: Person a: Address one object, two references IN THE STREAM writeObject(p1); writeObject(p2); p1 Person= h0 a Address= h1 p2 Person= h2 ref → h1 a again: only its handle on arrival, p1 and p2 again share one Address
Handles keep sharing intact. Without handles, the receiver would rebuild two separate Address copies, and a cycle (an object that eventually refers back to itself) would be serialized forever. The class description of Person is likewise written once and referred to by handle afterwards.

transient marks fields that must not be serialized, such as references to local resources like files and sockets, which mean nothing on another machine.

Reflection is what makes serialization generic. It is the ability of a program to inspect a class's name and its fields' names, types and values at runtime. So no per-class marshalling code is needed, unlike in CORBA. Deserialization uses it too: it loads the class by name, creates a constructor and fills in the field values.

public class Person implements java.io.Serializable {
    private String name, place;
    private int year;
    private transient java.net.Socket conn;          // not serialized: local resource
}
// sender: new ObjectOutputStream(sock.getOutputStream()).writeObject(person);
// receiver: Person p = (Person) new ObjectInputStream(sock.getInputStream()).readObject();
  • implements java.io.Serializable: permission to serialize; nothing to implement.
  • name, place, year: ordinary fields, serialized with their names and types.
  • transient … conn: skipped; after deserialization it is null.
  • writeObject(person) marshals the whole graph onto the socket's stream; readObject() rebuilds it and returns an Object, hence the cast (Person).

XML and JSON

The two text formats encode the same record as readable characters. (The guide's version also includes an id.)

<person id="123456789">
    <name>Smith</name>
    <place>London</place>
    <year>1984</year>
</person>
{"id": 123456789, "name": "Smith", "place": "London", "year": 1984}
XML: ELEMENTS, ATTRIBUTES, TAGS <person id="123456789"> <name>Smith</name> <place>London</place> <year>1984</year> </person> attribute: a simple labelled value start tag … end tag = one element elements nest, giving a hierarchy every value is text, even 1984 root element: person (exactly one) 73 bytes without the id and spaces JSON: AN OBJECT OF NAME/VALUE PAIRS { "id": 123456789, "name": "Smith", "place": "London", "year": 1984 } a number (native type) a string field names in teal no closing tags 45 bytes without the id and spaces
Same data, two text syntaxes. XML repeats every field name in an end tag and has only text; JSON names each field once and has native numbers. The byte counts are for the record without the id and without spaces, to compare with CDR's 28 bytes.
BYTES ON THE WIRE FOR {"Smith", "London", 1984} CORBA CDR 28 JSON 45 XML 73 binary and typeless is smallest; text with end tags is largest
Compact vs verbose, measured. The ordering matches the table: CDR compact, JSON lighter than XML, XML verbose. Java serialization is not drawn: it is binary like CDR, but adds the class name, version and field descriptions.

XML in more detail

XML (a W3C standard) is a textual, self-describing markup language. Its tags describe the data's structure, not its appearance, which is what distinguishes it from HTML. It is also extensible: users define their own tags, although applications that share documents must agree on them, as with SOAP's published tags.

  • Building blocks: elements, which nest and so can represent hierarchies, and attributes, which are labels for simple values. Any binary data is encoded as base64 (binary turned into text characters).
  • Well formed: tags match and are correctly nested, and there is a single root element.
  • Namespaces (xmlns:pers="URL") scope tag names to avoid clashes between vocabularies.
  • A schema defines the allowed elements and attributes, their nesting, order and types, so that a document can be validated. DTDs are an older, weaker way of doing this.

XML vs JSON trade-offs exam

Each format has advantages over the other, and you should be able to argue both directions.

XML over JSON
  • Richer self-description: namespaces avoid name clashes when several applications use one document.
  • Schemas and DTDs allow formal validation of structure and types, which strict contracts such as SOAP web services rely on.
  • Attributes, comments, and mixed text and markup; mature tooling (XPath, XSLT, signatures).
JSON over XML
  • More compact: no closing tags, so smaller messages and less bandwidth.
  • Faster and simpler to parse and generate: maps directly onto program data structures (objects, arrays, maps); it is JavaScript's own object syntax.
  • Native types (number, boolean, null, array) where XML has only text; easy for humans to read and write; dominant for REST APIs.

The two also have a lot in common: both are textual, human-readable and language-independent, and both are larger and slower than binary formats such as CDR or serialization. The tutors' point-by-point comparison is in 3.11.

Remote object references (CDK §4.3.4)

Marshalling also has to cope with references to objects in other processes. A remote object reference is "an identifier for a remote object that is valid throughout a distributed system". It is placed in invocation messages to say which object is to be invoked (Part VI).

Unique in space and time exam

A remote object reference must be unique in space and time. Space: unique across all processes on all computers. Time: never reused after its object is deleted, because clients may still hold old references, and invoking a deleted object must give an error and never reach a different object.

Internet address32 bits port32 bits time32 bits object number32 bits interface ofremote object the host together: the process, uniquely,on its host (never reused) a counter withinthat process which methodsit offers
Why the time field is there. A port number can be reused by a new process after the old one dies; adding the creation time makes (port, time) unique for ever, which gives the "unique in time" property. In simple RMI the reference also serves as the object's address; if objects are to be relocatable, it must not be used that way (CDK §8.3.3).
Check yourselfDefine marshalling. Compare CDR and Java serialization.

Marshalling translates data items into an external data representation for transmission, and unmarshalling rebuilds them on arrival. It is needed because of heterogeneity: machines differ in byte order, float formats and character sets.

CDR and Java serialization are both binary, but otherwise they take opposite approaches. CDR carries no type information, because both sides know the IDL; it is multi-language, sends values in the sender's byte order plus a flag, and uses marshalling code generated from the IDL. Java serialization carries the class name, version and field types, works in Java only, and is generic, using reflection.

Past exam 2016 Q4(b) · 2 marksGive a benefit of XML over JSON, and of JSON over XML.
  • XML over JSON. XML is self-describing, with namespaces and schemas, so documents can be validated against a formal definition and several vocabularies can be combined without name clashes. This suits strict contracts such as SOAP web services.
  • JSON over XML. JSON is more compact, because it has no end tags, and it is lighter and faster to parse. It maps directly onto programming-language data structures (objects and arrays; it is JavaScript object syntax), so it needs less bandwidth and processing.
Check yourselfWhat are Serializable, transient, handles and reflection for in Java serialization?
  • Serializable is a marker interface that allows a class's instances to be serialized.
  • transient excludes fields that refer to local resources, such as files and sockets.
  • Handles mean each object and class is written only once, with later references pointing to the handle. This preserves sharing and cycles.
  • Reflection discovers the class and its field names, types and values at runtime, so no per-class marshalling code is needed. It is also used to reconstruct the objects.
Check yourselfWhat does a remote object reference contain, and why must it be unique in space and time?

It contains the IP address, port, creation time, object number and interface. The port and time identify the process, the counter identifies the object, and the interface says which methods the object offers.

It must be unique across all processes, and it must never be reused after its object is deleted, so that a stale reference gives an error instead of reaching a different object.

Check yourselfWhich representation sends no type information at all?
  1. Java serialization
  2. JSON
  3. CORBA CDR
  4. XML

C. CDR sends only values; both sides know the types from the IDL. Java serialization sends full class information; JSON sends field names and basic types; XML sends tags.

Check yourselfIn CDR, why is "Smith" followed by three zero bytes?

Alignment: a primitive of n bytes must start at an index that is a multiple of n. "Smith" occupies bytes 4–8, so the next 4-byte value (the length of "London") must start at byte 12; bytes 9–11 are padded with zeros.

In short
  • Machines differ in byte order, float formats and character codes, so data is marshalled into an agreed external representation (or sent in the sender's format with a flag) and unmarshalled on arrival, usually by middleware.
  • CDR: binary, no type info (IDL), sender's byte order + flag, alignment padding, generated code. Java serialization: binary, full class info, handles for sharing, transient, generic via reflection, Java only. XML: text, tags, namespaces, schemas. JSON: text, compact, native types.
  • A remote object reference (address, port, time, object number, interface) must be unique in space and time.
3.9

Multicast Communication exam

Everything so far has been one process talking to one other. But some jobs need one process to talk to many: telling every replica of a database about an update, say. Sending a separate copy to each would be slow and would require knowing every member. Multicast solves this: it is sending one message from one process to every member of a group of processes, usually with group membership transparent to the sender.

sender need not be a member NETWORK copies made by the network → 228.5.6.7 : 6789 GROUP 228.5.6.7 member 1 member 2 member 3 member 4 one send()
One send, many deliveries. The sender addresses the group (teal), not the members (green); it does not know who they are or how many there are. Members can join and leave at any time.

Multicast has four uses:

Use 1

Fault tolerance

via replicated services: requests go to all the servers in a group, so clients are still served if some of them fail.
Use 2

Service discovery

in spontaneous networks, for example Jini: "who out there offers a printer?"
Use 3

Performance

via replicated data: updates are multicast to all the replicas.
Use 4

Event notification

as in publish-subscribe (Part VII).

IP multicast

In IP multicast, the sender transmits one IP packet to a multicast group, which is identified by a class D address: one whose first bits are 1110. The sender does not know who the members are or how big the group is. Membership is dynamic, so hosts can join and leave at any time, and you can send to a group without being a member.

first 4 bits 1 1 1 0 28 bits: which group range: 224.0.0.0 – 239.255.255.255 permanent groups are assigned by IANA, e.g. 224.0.1.1 = NTP; temporary groups must pick a free address (228.5.6.7, used in the code below, is in this range)
The address says "group". Any IPv4 address starting with the bits 1110 (first byte 224 to 239) names a multicast group rather than a single host.

For applications, IP multicast is available only through UDP. A socket joins the group, and every local socket that has joined and is bound to the destination port receives a copy, which makes this the one case where several processes share a port. Between networks, multicast routers forward the packets, and the TTL ("time to live") limits how many routers a packet may cross; Java's default of 1 keeps it on the local network.

LOCAL NETWORK ANOTHER NETWORK sender MEMBER HOST process 1 · :6789 process 2 · :6789 copy copy multicast router TTL = 1 (Java default) TTL used up: not forwarded member · :6789 reached only if the sender sets a larger TTL
Sharing a port, and how far a packet goes. Both member processes on one host are bound to 6789 and both get a copy: the one exception to "one receiver per port". The TTL counts router crossings; with Java's default of 1 the router does not forward the packet beyond the local network.

IP multicast's failure model exam

IP multicast has the same failure model as UDP: omission failures, which makes it unreliable multicast. A message may reach some members but not others. That can be caused by loss between routers (which affects every member beyond that router), by a recipient's buffer being full, or by a multicast router failing. There is also no ordering: one sender's messages can arrive in different orders at different members, and messages from different senders arrive in different orders too.

Unreliable, unordered multicast, message by message
S1 A B C S2 m1 buffer full m2 m3 A sees: m1, m2, m3 B sees: m2, m3 (no m1) C sees: m1, m3, m2
  1. Two senders, S1 and S2, and a group of three members A, B and C (green). Time runs to the right; a slanted arrow is a message in flight.
  2. S1 multicasts m1. A and C get it, but B's copy is dropped because B's buffer is full. This is an omission failure, and nobody is told: neither S1 nor A nor C knows that B missed it.
  3. S1 multicasts m2. This time all three get it, but the copy to C is slow.
  4. S2 multicasts m3. It reaches C before m2 does, but reaches A after m2.
  5. The result: the members have seen different sets of messages (B lacks m1) in different orders (A has m2 before m3, C has m3 before m2). If A, B and C were replicas applying these as updates, they would now disagree.

How much this matters depends on the use. Replicated services need every replica to receive every request, and in the same order, or the replicas diverge, whereas discovery can tolerate loss. Hence the need for stronger protocols, built in Part VII:

  • reliable multicast: a message is delivered to all members or none;
  • totally ordered multicast: all members see all messages in the same order.

Multicast in Java

MulticastSocket s = new MulticastSocket(6789);          // UDP socket on port 6789
InetAddress group = InetAddress.getByName("228.5.6.7"); // class D group address
s.joinGroup(group);                                     // now receives group traffic
s.send(new DatagramPacket(m, m.length, group, 6789));   // one send reaches all members
s.receive(packet);                                      // own and peers' messages
s.leaveGroup(group);  s.close();
LineWhat it does and why
new MulticastSocket(6789)A UDP socket bound to port 6789. (Multicast exists only over UDP.)
InetAddress.getByName("228.5.6.7")The group's class D address.
s.joinGroup(group)Becomes a member, so this socket now receives datagrams sent to the group. (Needed to receive, not to send.)
s.send(new DatagramPacket(m, m.length, group, 6789))An ordinary datagram addressed to the group: one send reaches every member bound to 6789.
s.receive(packet)Blocks until a group datagram arrives; a member receives its own messages as well as its peers'.
s.leaveGroup(group); s.close();Leaves the group and releases the socket.
Check yourselfWhat is IP multicast? Give its failure model and explain the need for stronger guarantees.

In IP multicast, one UDP datagram sent to a class D address (224–239.x.x.x) is delivered to all the members of a group. Membership is dynamic, senders need not be members, and the TTL limits how far the datagram spreads.

Its failure model is like UDP's. There are omission failures, where some members miss a message because of loss at a router, router failure or full buffers, and there is no ordering guarantee. Replicated services therefore need reliable multicast (all members or none) and totally ordered multicast, or the replicas become inconsistent.

Check yourselfWhich of these is a valid multicast group address?
  1. 128.250.25.158
  2. 192.168.1.1
  3. 230.1.2.3
  4. 255.255.255.255

C. Class D addresses run from 224.0.0.0 to 239.255.255.255 (first bits 1110). 230.1.2.3 is in range; the others are not.

Check yourselfA multicast-based service-discovery protocol and a multicast-based replicated bank account both run over plain IP multicast. Which one is in trouble, and why?

The replicated bank account. Every replica must apply every update in the same order, but IP multicast may drop a message at some members and deliver messages in different orders, so the replicas' balances diverge. Discovery can tolerate a lost message (the client just asks again).

In short
  • Multicast sends one message to every member of a group; uses: fault tolerance, discovery, replicated data, event notification.
  • IP multicast: one UDP packet to a class D address (224.0.0.0–239.255.255.255); dynamic membership; non-members can send; members on one host share the port; TTL limits the spread (Java default 1).
  • Same failure model as UDP: omission failures and no ordering, hence reliable and totally ordered multicast (Part VII).
3.10

Overlay Networks and MPI

The last two topics are brief in the guide (CDK §4.5 and §4.6), but both appear in the self-test, and the overlay flooding problem is modelled on a real 2016 exam question. Overlays answer the question "how do I get a network service the Internet doesn't provide, without changing the Internet?"; MPI answers "what does message passing look like when performance is everything?"

Overlay networks

Definition · overlay network

An overlay network is "a virtual network consisting of nodes and virtual links" built on top of an underlying network, such as IP. It provides a service tailored to a class of application, more efficient operation in a particular environment, or an extra feature such as multicast or security. It does this without changing the Internet itself, which fits the end-to-end argument (Part II).

OVERLAY: NODES AND VIRTUAL LINKS UNDERLYING NETWORK (IP): HOSTS, ROUTERS, WIRES 1 2 3 4 5 one virtual link router router …is several physical hops underneath
A network on top of a network. Overlay nodes (violet) are ordinary programs on ordinary hosts (squares); a virtual link between two of them is really a path through routers (circles). The gold link shows the extra level of indirection that is both the strength and the cost of overlays.
Advantages
  • New services can be added without changing routers or standards.
  • They allow experimentation and customisation.
  • Multiple overlays can coexist.
Disadvantages
  • An extra level of indirection, which costs performance.
  • Added complexity.

Overlays come in three types, grouped by what they are for:

TypeExamples
For application needsDistributed hash tables (key-based routing, usually on a ring), peer-to-peer file sharing, content distribution networks
For a network styleWireless ad hoc networks, disruption-tolerant networks
For extra featuresMulticast (the MBone), resilience, security (VPNs)

Case study: Skype

Skype is built on an overlay. Its super nodes are ordinary hosts chosen for their bandwidth, reachability (a global IP address, not hidden behind NAT, the address translation home routers do) and availability. Users log in through a central login server, searches for users run across the super nodes, and a call needs no IP address or port. For the calls themselves, TCP is used for call signalling and UDP is preferred for media, with TCP, possibly through a relay node, used to get through firewalls.

login server SN SN SN search for users runs across super nodes Alice's host Bob's host log in TCP: call signalling UDP preferred: voice and video media
TCP and UDP side by side. Signalling (setting up the call) must not be lost, so it uses TCP; the media stream values timeliness over completeness, so UDP is preferred, exactly the choice rule from 3.2. When a firewall blocks UDP, Skype falls back to TCP, possibly through a relay node.

Broadcast over an overlay of servers: flooding exam

In flooding, each server forwards a message to all its neighbours except the one it came from. This is safe only if the server graph is a tree (a connected graph with no loops). If a new server can connect to several existing servers, the graph has cycles, so copies circulate forever and members receive duplicates.

Flooding on a graph with a cycle, and the fixes
not in the tree A B C D origin A, B and C form a cycle:C joined by linking to both A and B m (id A:1) B: 2nd copy (from C) C: 2nd copy (from B) A gets m back, forwards again… D: duplicate seen A:1, drop seen A:1, drop seen-sets A: {A:1} B: {A:1} C: {A:1} D: {A:1} deliver and forward only the first time an id is seen or: spanning tree forward only on tree edges (here A–B, A–C, C–D); maintain the tree on joins and leaves; TTL as a safety net
  1. Four servers. D joined by linking to C only, but C joined by linking to both A and B, so A, B and C form a cycle. Each server forwards a message to all its neighbours except the one it came from.
  2. A broadcasts m (id A:1) to its neighbours B and C.
  3. B forwards to C (its only other neighbour), and C forwards to B and D (everyone except A). On a tree this would be the end.
  4. But now B and C each receive a second copy and, following the rule, forward it again: B back to A, C back to A and on to D. A forwards again… The message circulates forever, servers deliver duplicates, and traffic grows until the network is flooded.
  5. Fix 1: unique IDs and a seen-set. Every broadcast carries a globally unique id (origin server's id plus a sequence number, or a UUID). Each server remembers the ids it has seen, and delivers and forwards a message only the first time; B and C drop their second copies. A hop count / TTL can be added as a safety net.
  6. Fix 2: a spanning tree. Compute a tree that reaches every server (here, leave out the B–C link) and forward only along its edges. The tree needs maintenance when servers join or leave.
2016 Q2(a)-styleServers broadcast messages to each other by forwarding to their neighbours. If a new server can connect to several existing servers instead of just one, what major problem arises and how would you fix it?
  • Problem. With one connection per new server, the server graph is a tree, and "forward to all neighbours except the sender" reaches everyone exactly once. With several connections, the graph has cycles. A forwarded message comes back round a loop and is forwarded again, so it circulates forever. Servers deliver duplicates, and traffic grows until the network is flooded.
  • Fix 1. Give every broadcast a globally unique ID, made of the originating server's ID plus a sequence number, or a UUID. Each server keeps a set of IDs already seen: it delivers and forwards a message only the first time, and drops later copies. Optionally, add a hop count / TTL as a safety net.
  • Fix 2. Compute a spanning tree over the server graph and forward only along its edges. The tree needs maintenance when servers join or leave.
Check yourselfDefine an overlay network, with pros, cons and examples.

An overlay network is a virtual network of nodes and virtual links over an underlying network, offering a tailored service, efficiency or extra features. Its advantages are that the underlying network needs no change, that it allows experimentation, and that several overlays can coexist. Its disadvantages are the indirection, which costs performance, and the added complexity. Examples include DHTs, P2P file sharing, CDNs, the MBone and Skype.

MPI: the Message Passing Interface

MPI is a standard, from the MPI Forum in 1994, for message passing in high-performance computing (large parallel computations on clusters). It is portable, independent of the operating system and of language-specific socket APIs, and it has over 115 operations.

Its model is send and receive plus MPI library buffers at both ends. In MPI, blocking means "blocked until it is safe to return", that is, until the application's own buffer can be reused without corrupting the message.

SENDING PROCESS applicationbuffer MPI librarybuffer RECEIVING PROCESS MPI librarybuffer applicationbuffer network "safe to reuse" = blocking send may return
Buffers at both ends. Because the library keeps its own copy, a "blocking" MPI send can return as soon as the application's buffer is safe to overwrite, which is not necessarily when the message has been delivered. The four kinds of send below differ precisely in when they return.

There are four kinds of send, each in a blocking and a non-blocking form. The non-blocking forms return a handle at once, which you check later with MPI_Wait or MPI_Test.

SendBlockingNon-blocking
GenericMPI_Send: blocks until the message is in transit or deliveredMPI_Isend
SynchronousMPI_Ssend: returns only once the message is deliveredMPI_Issend
BufferedMPI_Bsend: returns once the data is copied into a user-attached buffer (MPI_Buffer_attach)MPI_Ibsend
ReadyMPI_Rsend: the programmer asserts the receiver is ready, so the handshake is skipped. It fails if that is wrongMPI_Irsend

The receives are MPI_Recv (blocking) and MPI_Irecv (non-blocking), and they combine freely with any send. In this way MPI separates the synchronous/asynchronous distinction from the blocking/non-blocking one, which 3.6 treated as linked. MPI also has collective operations, which include scatter (split data among processes) and gather (collect it back).

Check yourselfWhich MPI send returns only once the message has been delivered?
  1. MPI_Bsend
  2. MPI_Ssend
  3. MPI_Rsend
  4. MPI_Isend

B. MPI_Ssend, the synchronous send. MPI_Bsend returns once the data is in the user-attached buffer; MPI_Rsend skips the handshake on the programmer's word that the receiver is ready; MPI_Isend returns a handle immediately.

In short
  • An overlay is a virtual network of nodes and virtual links over IP, adding tailored services, efficiency or features (DHTs, P2P, CDNs, MBone, VPNs, Skype) at the cost of indirection and complexity.
  • Flooding on a graph with cycles makes messages circulate forever; fix with unique ids plus seen-sets (and a TTL), or a spanning tree.
  • MPI: HPC message passing with library buffers; "blocking" means safe to reuse the buffer; four sends (generic, synchronous, buffered, ready) × blocking/non-blocking.
3.11

Pitfalls and Tutorials 2 & 4

This last section gathers the mistakes that lose marks, a design question that pulls the whole Part together, and the official tutor answers from Tutorial 2 (Week 3: sockets, UDP and TCP) and Tutorial 4 (Week 5: data representation). Staff have confirmed the tutorial answers are examinable.

Common pitfalls

Mistakes that lose marks
  • Two common beliefs are both false: that "TCP is fully reliable" (3.7), and that "one write equals one read" (3.4).
  • Mismatched reads and writes, such as writeUTF paired with readLine, or a missing flush, leave the reader with garbage or blocked forever.
  • new Socket(host, port) creates a client, never a server.
  • client.close() closes one connection, not the ServerSocket. Close sockets explicitly rather than relying on garbage collection.
  • With UDP, a receive with no timeout hangs forever if a datagram is lost.

Putting it together: a design question

ScenarioDesign the transport and message format for a multi-client enrolment (or dictionary) server.
  • TCP. Requests change shared state, so they must not be lost, duplicated or reordered, and TCP provides that. The cost of setting up the connection is spread over the many requests in a session.
  • Framing. TCP has no message boundaries, so the messages must be delimited (one JSON object per line, read with readLine, with a flush on every write) or length-prefixed. Either way, partial reads are handled.
  • JSON. It is language-independent and debuggable, unlike Java serialization, which ties both ends to Java and to class versions.
  • Concurrency. Use a multithreaded server (thread-per-connection or a worker pool, Part IV) with per-item locking, and handle EOFException and IOException when a client disconnects.

Tutorial 2 (Week 3): sockets, UDP and TCP official answers

Tutorial 2 · Q1Briefly discuss three aspects of the socket interface.
  • A socket is bound to a local port, and a socket address is IP address + port number.
  • Sockets are used for communication, sending and receiving data, between two networked processes.
  • Each socket is associated with one protocol, UDP or TCP.
  • The socket interface is the programming interface between application code and the transport layer, and a socket handle is used much like a file handle.
Tutorial 2 · Q2Briefly explain three failures that can happen when using UDP.
  • Data corruption can happen because UDP's checksum is optional.
  • Omission failures happen because delivery is not guaranteed, so datagrams can be dropped.
  • Ordering failures happen because datagrams can arrive out of sender order.
Tutorial 2 · Q3Briefly explain the aspects of TCP that address issues UDP does not.

The tutors pair each UDP problem with the part of TCP that answers it:

UDP problemTCP's answer
No connectionConnection-oriented: the client sends a connect request and the server accepts it before any data flows
Size limit of 64 KBNo limit on the amount of data an application can send
Can lose messagesAcknowledgements; unacknowledged data is retransmitted
A fast sender swamps the readerFlow control matches the writer's speed to the reader's
Allows duplication and reorderingMessage identifiers (sequence numbers) let the receiver reject duplicates and reorder segments
Tutorial 2 · Q4List the steps at the client and at the server to establish a TCP stream socket connection.

The tutors' answer is the TCP three-way handshake, stepped through below, together with the Java calls on each side:

  • Server. The server creates a socket bound to a known port (new ServerSocket(port)), which listens. accept() blocks until a client connects and then returns a new socket for that client. The server reads and writes that socket's streams, then closes it.
  • Client. The client creates a socket naming the server's host and port (new Socket(host, port)). This sends the connect request (SYN) and returns once the handshake is complete. The client then gets the input and output streams, reads and writes, and closes the socket.
  • The TCB (transmission control block) is the per-connection state each end keeps. It is the "state at both ends" listed among the costs of reliable delivery (3.2).
The TCP three-way handshake (Tutorial 2, Q4)
client (initiator) server (listener) socket bound to a known port,listen() 1 · SYN connect() TCB initialised inSYN-RECEIVED state 2 · SYN-ACK connect() returnssuccess 3 · ACK TCB → ESTABLISHED;accept() returns data exchanged on the stream, both directions
  1. The server's socket is bound to a known port and listening (new ServerSocket(port); accept() is waiting).
  2. The client calls connect() (in Java, inside new Socket(host, port)), which sends SYN, a "let's synchronise" connection request.
  3. The server creates its per-connection state, a TCB (transmission control block), in the SYN-RECEIVED state.
  4. The server replies SYN-ACK: it acknowledges the client's SYN and sends its own.
  5. On receiving SYN-ACK, the client's connect() returns success.
  6. The client sends the final ACK, acknowledging the server's SYN.
  7. The server's TCB moves to ESTABLISHED, and accept() returns the new per-client socket.
  8. Both ends now hold connection state, and data is exchanged on the stream in both directions.

The tutors' summary of UDP versus TCP matches 3.2. UDP is the simplest connectionless IPC: it offers a message-passing abstraction and sends single datagrams, and it is used for real-time video streaming, DNS and NTP. TCP offers a two-way stream with no message boundaries. It is the basis for producer/consumer communication, in which data is queued until the consumer is ready and the consumer waits when no data is available. It is used for HTTP and FTP.

Tutorial 4 (Week 5): data representation, XML and JSON official answers

The marshalling material repeats 3.8, including the two approaches: convert to an agreed external format, or send in the sender's format with an indication of which format it is. The tutors' XML vs JSON comparison, though, adds points to the trade-offs in 3.8. The table lines the two formats up point by point:

PointJSONXML
SimplicityLightweight, so simple to read and writeLess simple than JSON
Data typesHas scalar data types, and expresses structured data through arrays and objects (native object support)No notion of data types: XML Schema is needed to add type information
ArraysSupports arraysNo array structure. Objects are expressed by convention, often a mix of attributes and elements
ReadabilityMore human-readableLess human-readable
Message sizeSerialises to shorter strings, so less data is transmitted and performance improvesText-heavy (closing tags), so messages are larger
DisplayNo display capabilitiesCan be used to display data because it is a markup language
Caution on "display"

CDK stresses that XML tags describe structure, not appearance (3.8). What the tutors mean is that XML can be transformed into a presentation, for example with XSLT stylesheets, so if you use this point, phrase it that way.

How this is examined

The 2016 paper asked exactly this (Q4(b): a benefit of XML over JSON and vice versa), so learn both columns. The same paper's Q4(a) asked for three TCP/UDP differences. For both, name the dimension first ("Message size: …", "Validation: …") and then give each side; that is what earns each mark.

Check yourselfA classmate writes "XML is better than JSON because XML has data types". What's wrong, according to the tutors' table?

It's backwards. XML itself has no notion of data types (everything is text); XML Schema is needed to add type information. JSON has scalar types (number, boolean, null) and arrays natively. A correct XML-over-JSON benefit is that schemas allow formal validation, and namespaces avoid name clashes.

In short
  • Never claim TCP is fully reliable or that one write equals one read; match reads to writes and flush; new Socket is always a client; time out UDP receives.
  • Tutorial 2: socket = (IP, port), one protocol, file-like handle; UDP failures = corruption (optional checksum), omission, ordering; TCP answers each UDP gap; connection set-up is the SYN, SYN-ACK, ACK handshake, with a TCB at each end.
  • Tutorial 4: JSON is simpler, typed, has arrays and is smaller; XML needs Schema for types, has no arrays, is larger, and can be transformed for display.