“'Mr Bassington-Bassington has just telephoned, sir.'”

CS644 week 6: Networking

Main page: /cs644/summer2026

Last week

Link: /week4 (Week 5 was the mid-course break.)

Review

Solutions

Networking basics

Networking – communication between two or more computers over a wired or wireless link – is fundamental to modern computing. It is also a much bigger topic than we can hope to cover in a single week, so we will concentrate on how to use the Linux sockets API, which was first introduced in Week 4, to communicate via a couple of the most popular protocols.

For two computers to communicate successfully with each other, they must agree on a protocol. This is not so different from two different programs on the same computer, or even two different parts of the same program, which have to agree on the order of arguments, whether they are placed on the stack or in registers, etc. But network protocols have to contend with many more sources of complexity, notably, the possibility (indeed, the likelihood) that the connection between the two computers is unreliable, and the possibility that the two computers are running different operating systems or even different CPU architectures. Consequently, network protocols are complicated.

In fact, when your computer talks to another computer, there is not just one network protocol at play. A 2000s-era connection between your desktop computer and a web server might look something like:

This layering of protocols is called the protocol stack. Each layer is responsible for a specific concern:

High-level protocols like HTTP can be simple (indeed, it is quite easy to write a basic HTTP/1.1 client and server) because the low-level protocols hide the details of how packets make their way across our gigantic, planet-scale integrated network.

Networking in 2026

We described a typical Internet connection in the 2000s. In 2026, the basic picture is the same, but the details may be different. You're more likely to use an 802.11 Wi-Fi connection than a fixed Ethernet link. IPv4 is still prevalent, but many connections now use the next version of the protocol, IPv6. The transport protocol might be QUIC, a more efficient transport-layer protocol designed at Google, rather than TCP, and you are most likely making an encrypted connection with TLS on top of TCP or integrated with QUIC. HTTP is still king, but instead of HTTP/1.1 you could be using HTTP/2 or even HTTP/3 (which uses QUIC).

Networking in Linux: TCP and UDP

That was a whirlwind tour of the network stack. For the purposes of this class, we are going to home in on the two dominant transport-layer protocols: TCP and UDP. These are the protocols at the interface between the kernel and userspace: lower-level protocols like Ethernet and IP are handled entirely inside the kernel, while higher-level protocols like HTTP are handled entirely in userspace.

A quick aside

Why does the kernel need to be involved with networking at all? It needs to be involved at the link layer because that requires controlling physical hardware (your computer's NIC). It needs to be involved at the network and transport layers because many processes may be doing networking at once and the kernel needs to ensure that each process gets its own incoming packets and no one else's.

We've already briefly mentioned TCP: it's a reliable, connection-oriented, byte-stream protocol, built on top of IP. UDP, the User Datagram Protocol, is likewise atop IP, but it is instead a unreliable, connectionless, datagram protocol.

TCP is ideal when you want to guarantee that data is transmitted reliable (think HTTP or SSH) and you are willing to sacrifice a little bit of performance (because of, e.g., head-of-line blocking from packet retransmission). UDP may be more appropriate if it is acceptable to sometimes drop packets (e.g., streaming video or audio), or if you want to build your own application-specific "reliable transmission" semantics.

Addresses, domain names, and ports

A host on an IP network is identified by an IP address. In IPv4, addresses are 32 bits and are written like 167.71.190.147, with each decimal number representing 4 bytes. 32 bits only allows for 4 billion unique addresses, which is not enough for the modern Internet, so IPv6 expanded addresses to 128 bits. IPv6 addresses look like 2001:db8::8a2e:370:7334.

As an Internet user, you almost always interact with human-readable domain names, like iafisher.com, rather than raw IP addresses. A network protocol called DNS lets you dynamically map a domain name to the underlying IP address.

An IP address identifies a host on a network, but a single host may offer many networked services. For instance, a web server may accept both HTTP connections from its users, and SSH connections from its administrators. TCP and UDP introduce the concept of a port, an integer that identifies a particular service at an address. There are conventional ports for different services, for instance port 22 for SSH, port 80 for HTTP, and port 443 for HTTPS, but nothing stops you from using a different port, as long as the client and server agree.

A port is a TCP/UDP software abstraction. It is not a physical interface on your computer.

The sockets API for networking

In Week 4, we learned how to use the sockets API for interprocess communication via Unix domain sockets. It turns out that the exact same API is used for communication between different computers.

As a refresher, for a stream-oriented connection:

In Week 4, we used socket.AF_UNIX as the first argument to socket.socket to create a Unix domain socket. For IPv4 networking, we instead pass socket.AF_INET. The second argument can still be socket.SOCK_STREAM or socket.SOCK_DGRAM, but with AF_INET these two values refer to two specific networking protocols: TCP for SOCK_STREAM and UDP for SOCK_DGRAM.

Exercise: Make an HTTP request

Exercise: Use the sockets API to retrieve the contents of http://example.com (note the use of HTTP, not HTTPS).

Exercise: Write a UDP server

Exercise: Write a server program and a client program that speak UDP to each other. You can have the server do whatever you'd like: echo the client's message unchanged, return the message reversed, etc. Bind the server to ("localhost", port), where port is equal to your user ID plus 1000. (You can get your user ID from the shell by running id -u.)

Final project milestone

Extend the client–server interface you added last week to support real networking. Add an --ipc flag to your server that can be unix, fifo (if you implemented it last week), udp, or tcp.

For UDP: implement your own reliable-message semantics, i.e., the client should detect if a message was received, and retry if not.

For TCP: make sure there is some way to detect message boundaries in the bytestream, so that a client can send multiple messages on the same connection.

Listen on port uid + 1000 for UDP and port uid + 2000 for TCP, where uid is your user ID as printed by id -u in the shell. For example, if id -u prints 1008, then use ports 2008 and 3008. This ensures that you don't interfere with your classmates.

Bonus material