CS644 week 6: Networking
Main page: /cs644/summer2026
Last week
Link: /week4 (Week 5 was the mid-course break.)
Review
- Concepts: Pipes, FIFOs, Unix domain sockets
- Syscalls:
os.pipe,os.mkfifo,socket.socket,socket.bind,socket.connect,socket.listen,socket.accept,socket.send,socket.recv
Solutions
- Pipe edge cases:
week4/pipe_edge_cases.py - Pipes and fork:
week4/pipe_fork.py - FIFOs:
week4/myfifo.py - UDS client and server:
week4/uds_server.py - UDS edge cases:
week4/uds_edge_cases.py
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:
- The desktop communicates with your home router via a wired Ethernet connection.
- Inside the Ethernet packets are IPv4 packets that go all the way across the Internet backbone to the web server.
- The IPv4 packets are themselves used to carry a stream of TCP data.
- The TCP data encodes an HTTP/1.1 request to fetch a resource from the web server.
This layering of protocols is called the protocol stack. Each layer is responsible for a specific concern:
- Ethernet handles the physical transmission of data across a fixed link between a sender and a receiver (the link layer).
- The Internet Protocol (IP) routes data from one point to another point across an entire network, where the sender and receiver may be many hops away from each other (the internet layer).
- The Transmission Control Protocol (TCP) handles congestion control and packet loss, and presents an abstraction of a stream of data rather than a sequence of discrete packets (the transport layer).
- The Hypertext Transfer Protocol (HTTP) is an application-specific protocol for transferring documents (the application layer).
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.
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.
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.
- Reliable vs. unreliable: Does the protocol keep track of sent and received packets and retransmit any that were dropped (TCP), or are dropped packets simply lost (UDP)?
- Connection-oriented vs. connectionless: Does the protocol maintain a persistent connection between the two hosts (TCP), or not (UDP)?
- Stream vs. datagram: Do users of the protocol read and write streams of data without message boundaries (TCP), or are there discrete messages (UDP)?
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:
- Server calls
socket.socket,socket.bind,socket.listen,socket.accept. - Client calls
socket.socket,socket.connect.
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).
connectfor a TCP socket in Python takes a tuple of(host, port). In this case, it should be("example.com", 80)– 80 is the standard part for HTTP connection. It isexample.comand nothttp://example.comsince the former is the actual domain name, while the latter is the URL as you would type it in a browser.- HTTP is a simple text-oriented protocol. The message you want to send on the socket is
b"GET / HTTP/1.1\r\nHost: example.com\r\nUser-Agent: python/3.12.3\r\nAccept: */*\r\n\r\n".
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.)
- UDP servers do not call
listenoraccept, since they are connectionless. Instead, they callrecvfrom, which returns a tuple(bytes, address). The server can use the address to respond withsendto. - A UDP client can call
connectand thensendandrecv, but it can also callsendtowithout needing to callconnectfirst.
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
- Beej's Guide to Network Programming – Goes into a lot more depth on how to use the networking APIs. Highly recommend!