Core CS · Computer Networks
IP finds the machine, the port finds the program
Every packet arriving for your laptop carries exactly one destination address, and that address names the machine and nothing else. Sixteen bits in the transport header close the gap to the process. Four numbers rather than two are what let one server port hold ten thousand conversations without mixing a single byte.
Step seven segments through one host and watch the four-tuple decide →01 The idea
The network layer stops at the front door
An IP packet carries exactly two addresses, and both of them name machines. Every router between here and there reads the destination address, looks it up in a table, and forwards; the previous module was entirely about how that lookup works. When the packet finally lands at 10.0.0.5, the network layer has finished its whole job, and what it has achieved has a name: host-to-host delivery. The right bits are on the right machine.
That is not what any application asked for. The machine at 10.0.0.5 is running a web server, an SSH daemon, a DNS resolver and a hundred other processes, and nothing in the IP header says which of them this packet belongs to. Closing the gap between the right machine and the right program on that machine is process-to-process delivery, and it is the first and most basic thing the transport layer does. Everything else transport can offer you is optional. This part is not, which is why even UDP, which declines almost everything, still has ports.
The mechanism is one number. The transport layer puts its own header in front of the application data, and the first four bytes of that header, in both TCP and UDP, are two 16 bit fields: the source port and the destination port. A TCP header is 20 bytes when no options are set and can reach 60 bytes with them. A UDP header is 8 bytes and never changes size. In both, the two ports come first, and that ordering is not decoration: they are the first thing the receiving host needs to read.
Sixteen bits gives 2¹⁶ = 65,536 distinct values, numbered 0 to 65535. Say 65,536 values, or say the range 0 to 65535, and both are right. Saying “65,535 ports” is the small slip that gets picked up, and you get that many per transport protocol rather than in total, which section 03 comes back to.
Now the pairing. An IP address on its own identifies a machine. A port on its own identifies nothing at all, because port 80 exists on every machine on the Internet. Put them together and you have an endpoint that is unique in the world, 10.0.0.5:80, and that pair is a socket. Here is the refinement the rest of the lesson turns on: a socket is enough to name an endpoint, but it is not enough to name a conversation. Two clients talking to that same 10.0.0.5:80 are two different conversations, and the host has to keep them apart with something. That something is the other end of each one.
02 Worked example
One click, from the source port to the right socket
This is the scene for the whole lesson. A laptop at 203.0.113.7 opens a page on a web server at 10.0.0.5. That server is also running sshd and a DNS resolver, so it holds five sockets in all, and it is the same host the console in section 04 runs. Read the five nodes left to right. The highlighted one is where the decision actually happens; the other four are setting it up.
Count what changed between the fourth node and the fifth. Three of the four numbers were identical and one differed, and that one number is the whole difference between two mixed-up tabs and two clean conversations. State the argument in that form and it is hard to forget: the destination pair says which door, the source pair says which visitor, and a server needs both to answer the right person. A demultiplexer keyed on the destination pair alone would have dropped both tabs into one buffer, and the reply to the second request could be painted into the first tab.
The reply direction is worth a sentence, because it is the same mechanism with the fields swapped. When the server answers, its source becomes (10.0.0.5, 80) and its destination becomes (203.0.113.7, 52310). The laptop then runs the identical four-field lookup on the way in. Nothing about this is asymmetric, which is why the proper name for the four numbers is a socket pair: one socket at each end, and the connection is the pair.
One caution about the first node, because it is exactly the sort of detail an interviewer follows up on. IANA calls 49152 to 65535 the dynamic or private range, and that is the answer to give when asked where a source port comes from. Linux does not use it: the default value of net.ipv4.ip_local_port_range is 32768 60999, which dips well into the registered range. Windows has used the IANA range since Vista. Give the standard, then name the difference in one clause, and the follow-up question stops there.
03 Mechanics
The ranges, the ports, and the two demultiplexers
Four tables, in the order the questions arrive. First the three ranges. The boundaries are exact numbers and they get asked for as exact numbers, so the count column is there to be checked: the three add up to 65,536 or one of your boundaries is wrong.
| Range | Numbers | How many | Who assigns them | Where you meet it |
|---|---|---|---|---|
| Well-known (system) | 0 to 1023 | 1,024 | IANA, through a standards process | The server side of every protocol in the next table. Binding one on Linux or macOS needs root, or the CAP_NET_BIND_SERVICE capability. |
| Registered (user) | 1024 to 49151 | 48,128 | IANA on request, but no privilege is needed to bind one | MySQL 3306, PostgreSQL 5432, Redis 6379, Tomcat 8080. Everything you run in a lab lives here. |
| Dynamic (private, ephemeral) | 49152 to 65535 | 16,384 | Nobody. The kernel picks a free one per outgoing connection | Your own source port, every time you open a connection. You never choose it and you rarely look at it. |
| The three must total the field width. 1,024 + 48,128 + 16,384 = 65,536, which is 2¹⁶. Count a range inclusively at both ends: 49151 − 1024 + 1 = 48,128. Dropping the + 1 is where the off-by-one comes from. | ||||
What the privilege on the first range is actually protecting. A well-known port carries an implied promise about what is listening there: connect to port 25 of a mail server and you expect SMTP. If any user on a shared machine could bind port 25, any user could impersonate that promise. So Unix systems refuse the bind below 1024 unless the process is root or holds CAP_NET_BIND_SERVICE. In production the three usual answers are to grant that one capability instead of running as root, to let systemd open the socket and pass the descriptor to an unprivileged process, or to listen on 8080 and put a reverse proxy in front.
Now the list. These are the ports a placement interview actually asks for, and the transport column is asked for as often as the number.
| Port | Service | Transport | What to say about it |
|---|---|---|---|
20 | FTP data | TCP | Carries the file itself. In active mode the server opens this connection back towards the client. |
21 | FTP control | TCP | Commands and replies. Two ports for one protocol is why FTP gets asked about at all. |
22 | SSH | TCP | Also carries scp and sftp, so one port covers three tools. |
23 | Telnet | TCP | The same job as SSH with nothing encrypted. Name it as the thing SSH replaced. |
25 | SMTP | TCP | Relay between mail servers. |
53 | DNS | UDP and TCP | UDP for ordinary queries, TCP when the response will not fit or for a zone transfer. The only row here with two transports. |
67 | DHCP server | UDP | The server listens here. |
68 | DHCP client | UDP | The client listens here. Both ends are fixed because the client has no address yet and must broadcast. |
80 | HTTP | TCP | The default when a URL has no port. |
110 | POP3 | TCP | Downloads mail and by default removes it from the server. |
143 | IMAP | TCP | Leaves mail on the server, which is why every phone uses it. |
443 | HTTPS | TCP | And UDP 443 for HTTP/3 over QUIC, which is the modern follow-up question. |
587 | SMTP submission | TCP | Client to server, authenticated. 25 is relay, 587 is submission, and swapping them is the trap. |
Two rows worth one extra sentence each. DNS uses UDP because a query and its answer are one small exchange, and paying a handshake round trip to look up an address would double the cost of every page load. The classic limit is 512 bytes of DNS payload in a datagram; if the answer is larger, the server sets the truncated bit and the resolver asks again over TCP 53, and the EDNS0 extension raises that limit to negotiate larger datagrams instead. DHCP is stranger: the client has no IP address at the moment it asks for one, so it sends from 0.0.0.0:68 to the broadcast address 255.255.255.255:67. Both ports must be fixed and well-known because neither end can be told the other’s ephemeral port in advance.
This is the table the lesson is really about. Same job on both sides, and a genuinely different amount of work.
| Demultiplexing | UDP | TCP |
|---|---|---|
| A socket is keyed on | dest IP, dest port — 2 fields | src IP, src port, dest IP, dest port — 4 fields |
| The source fields are | read, but not used to choose the socket. Handed to the application beside the payload | part of the key, and compared on every arriving segment |
| Two clients to the same server port | one socket, both datagrams land in it | two sockets, one per client |
| Sockets the server holds | one, for as long as the process runs | one listening socket plus one per live connection |
| API shape | socket, bind, then recvfrom in a loop | socket, bind, listen, then accept, which returns a new socket each time |
| Nothing bound on that port | ICMP type 3 code 3, port unreachable | TCP RST segment |
| Header cost | 8 bytes, fixed | 20 bytes minimum, 60 with options |
| Selected by | IPv4 protocol field 17 | IPv4 protocol field 6 |
Listening sockets, and the 0.0.0.0 you keep seeing. A listening socket never carries data. It sits at a local address and port with a wildcard peer, written *:*, and its only job is to catch a SYN for a connection that does not exist yet; accept then hands you a brand new socket pinned to that one four-tuple, and every byte flows through the new one. The local half of a socket is an address and a port, not a port alone, and that has a consequence people meet the hard way. A server that binds 10.0.0.5:8080 has claimed that port on one interface only, so a second process can bind 192.168.1.9:8080 on another interface and both succeed. Bind 0.0.0.0:8080 instead and you are asking for that port on every interface at once, which is what most servers do by default and what ss prints as 0.0.0.0:8080 or *:8080.
Two separate port spaces, not one. TCP and UDP each get their own 65,536 numbers, because the IPv4 protocol field is consulted before the port table is. A process can hold TCP 53 while a completely different process holds UDP 53, and neither bind fails. That is not a corner case; it is exactly how a DNS server is normally deployed, and it is why “is port 53 free” is not a well-formed question until you say which protocol.
Last, what the transport layer is actually offering. Read this column by column rather than row by row: TCP is a bundle, and UDP is what is left when you decline the bundle.
| Service | TCP | UDP | If you pick UDP, who does it |
|---|---|---|---|
| Process-to-process delivery | yes | yes | Neither can decline this. It is what a port is for. |
| Error detection over the payload | yes, checksum mandatory | checksum optional in IPv4, mandatory in IPv6 | The application, or nobody. |
| Reliable delivery | yes, acknowledgements and retransmission | no | The application. A DNS resolver asks again after a timeout. |
| In-order delivery | yes, sequence numbers reorder the stream | no | The application. RTP carries its own sequence number for this. |
| Flow control | yes, the receive window | no | Nobody. A fast sender can drown a slow receiver. |
| Congestion control | yes | no | The application. QUIC implements it in user space over UDP. |
| Connection setup cost | a three-way handshake, one round trip before any data | none, the first datagram carries data | — |
A menu, not a mandate. The rows above are services the transport layer offers, and the interesting thing about UDP is not that it lacks them but that declining them is a design decision somebody made on purpose. Live audio does not want retransmission, because a frame that arrives 200 milliseconds late is useless however perfectly it arrives, and worse, TCP would hold every later frame behind it while it recovered the lost one. A DNS query does not want a handshake, because the handshake would cost more than the query. So the honest summary of the whole layer is this: process-to-process delivery is compulsory, everything else is a menu, and UDP is the order that takes the first item and nothing else.
05 Cheat sheet
The numbers to have ready
Every row is something you can be asked to state in under ten seconds. The right-hand column is the specific wrong answer that gets given, not a general caution.
| What they ask | The answer | The trap |
|---|---|---|
| Width of the port field | 16 bits, 65,536 values, 0 to 65535 | saying 65,535 ports — and forgetting it is per protocol |
| Well-known range | 0 to 1023, which is 1,024 numbers | Saying 1 to 1024. Binding one on Unix needs root or CAP_NET_BIND_SERVICE. |
| Registered range | 1024 to 49151, which is 48,128 numbers | Claiming it runs to 65535, which erases the third range entirely. |
| Dynamic or ephemeral range | 49152 to 65535, which is 16,384 numbers | quoting IANA as what Linux does — its default is 32768 to 60999 |
| What a socket is | one IP address plus one port, 10.0.0.5:80 | calling the four-tuple a socket — that is a socket pair, which is a connection |
| What names a TCP connection | src IP, src port, dest IP, dest port | Giving two fields, which merges every client on one server port into one stream. |
| What UDP demultiplexes on | destination IP and destination port | claiming UDP uses the four-tuple too — it has no connections to separate |
| TCP segment to a closed port | a RST segment | Saying ICMP. A firewall dropping it silently is a third outcome and not the protocol’s. |
| UDP datagram to a closed port | ICMP type 3 code 3, port unreachable | Saying RST. UDP has no connections, so it has no reset. |
| Header sizes | TCP 20 bytes min, 60 with options; UDP 8 fixed | Quoting the TCP header as a flat 20. It is a minimum. |
| TCP 80 and UDP 80 | two different sockets, two separate port spaces | one shared table of 65,536 ports per machine |
| The ports to memorise | 20 21 22 23 25 53 67 68 80 110 143 443 587 | 25 versus 587 — 25 is relay between servers, 587 is authenticated submission |
06 Where & why
Where these numbers show up on a real machine
None of this is a teaching abstraction. Each of these four is a socket table with a local pair, a remote pair, a rule for choosing a row, and a fixed answer when no row matches. Two of them differ from the textbook in a way worth naming out loud.
ss -tan prints one line per TCP socket with the local address and the peer address side by side, which is the four-tuple with the fields in that order. A LISTEN row shows a peer of *:*, meaning any remote endpoint; an ESTAB row shows a real one. Run it with a browser open and you will see several rows sharing one server address and differing only in the client port. The ephemeral ports it draws from are set by net.ipv4.ip_local_port_range, whose default is 32768 60999 and not the IANA 49152 to 65535.
sshd binds TCP 22, which is inside the privileged range, so it starts as root and drops privileges afterwards. Changing Port 22 to Port 2222 in sshd_config moves it into the registered range where an unprivileged user can bind it, and every client then has to be told with ssh -p 2222, because nothing in the protocol advertises the move. That trade, one privileged default against one extra argument forever, is the well-known range doing exactly its job.
A worker holds one listening socket on port 443 and one further socket per live connection, all sharing that same local pair and differing only in the remote half. worker_connections caps how many it will keep, and the operating system open-file limit caps it again, because every socket is a file descriptor. When several workers need to accept in parallel they use SO_REUSEPORT to each hold their own listening socket on the same port, and the kernel spreads arriving connections across them by hashing the four-tuple.
A resolver at 8.8.8.8:53 is reached over UDP by clients that have no connection to it and never had one. Every query lands in the same socket, and the server learns who sent it from the sender address delivered beside the payload, which it then uses as the destination of the reply. The same address answers on TCP 53 when a response will not fit in one datagram, and on TCP 443 for DNS over HTTPS, which exists largely to get through networks that filter port 53.
07 Interview questions
What they ask, and what they follow up with
This topic is asked early in an interview because it is cheap to check and expensive to fake. The pattern is that a definition question is followed immediately by a number question, so give the boundary values without being asked for them; that one habit does more for you here than any amount of extra theory.
What does the transport layer give you that the network layer cannot?
What exactly is a port number, and how many are there?
Give me the three port ranges with their boundaries.
What is a socket, and is a socket the same thing as a connection?
Two browser tabs are open on the same website. Why do the responses not get mixed up?
How is UDP demultiplexing different from TCP demultiplexing?
A segment arrives for a port with nothing bound. What happens?
Why does binding to port 80 need root?
Where in the packet are the port numbers, and why does the answer matter?
Define multiplexing and demultiplexing in one sentence each.
TCP gives you strictly more than UDP. So when would you actually choose UDP?
08 Practice problems
Six to work on paper
Write every four-tuple out as four separate numbers before you decide anything, even where the answer looks obvious. Two of these six turn on the fact that a socket has a local half with two parts in it, and one of them cannot be answered at all until you notice which field a middlebox is allowed to change.