pete > courses > CS 431 Spring 25 > lecture 13: TCP concepts


Lecture 13: TCP concepts

Goals


recall that there are many problems IP does not solve

we solved one of them in UDP: the addition of port numbers allows us to send stuff (datagrams) to an individual process that has bound to a particular port on the receiving host

but several potential problems remain:

I say "potential" because it’s possible the functionality we want to implement doesn’t suffer from these much

but there are a lot of applications that are sensitive to these problems, and so it makes sense to have a protocol that doesn’t have them

enter: the Transmission Control Protocol (TCP)


like UDP, TCP is built directly on top of IP

also like UDP, TCP includes a notion of ports (also using 16-bit values) that allow data to be addressed to individual processes

unlike UDP, TCP is a stream-oriented protocol

in UDP, which is a datagram-oriented protocol, each unit of communication is of finite size, the sender sends a datagram and the receiver receives that datagram

in TCP, the sender just sends a stream of bytes and the receiver receives that stream of bytes: the receiver does not know if/how the data it receives was divided up into smaller parts for sending

in UDP, if a datagram is sent but doesn’t make it to the receiver, the receiver doesn’t know (unless there is some data embedded in the datagram itself, by the sender, that the receiver can use to figure this out…)

in TCP, if a unit of data disappears, it will automatically be detected and re-sent, and the receiver won’t even know: it will just see the uninterrupted sequence of bytes


now, some terminology

in Ethernet, the data unit is a frame

in IP, it’s a packet

in UDP, it’s a datagram

in TCP, we’re going to use the term segment

so a TCP stream consists of a sequence of segments that contain the data being transmitted


because TCP attempts to handle many different circumstances, some of which are somewhat complicated, we need a good way to describe and think about the sending and receipt of segments

for that purpose, we will use ladder diagrams

in a ladder diagram, the entities involved (eg, hosts) are represented by vertical lines and frames/packets/segments sent between them are represented by arrows between those vertical lines

time starts at the top, and proceeds down, so the frame/packet/segment sent furthest in the past will be at the top of the diagram and the most recent will be at the bottom

example:

  Process A |   segment 1   | Process B
            | ------------> |
            |               |
            |   segment 2   |
            | <------------ |
            |               |
            |   segment 3   |
            | <------------ |
            |               |
            |   segment 4   |
            | ------------> |
            |               |

this diagram represents the situation wherein Process A sends segment 1 to Process B

then Process B sends back segment 2, followed by segment 3

and finally Process A sends segment 4 back to process B


using ladder diagrams, we can illustrate the situations that we want TCP to identify and fix for us

a segment is lost:

  Process A |   segment 1   | Process B
            | ------------> |
            |               |
            |   segment 2   |
            | ------>       |
            |               |
            |   segment 3   |
            | ------------> |
            |               |

a segment arrives out of order:

  Process A |   segment 1   | Process B
            | ------+       |
            |       |       |
            |   segment 2   |
            | ------------> |
            |       |       |
            |       +-----> |

the "segment is corrupted during transmission" case is handled by more checksums, where the segment is discarded if the checksum fails, and therefore operates just like a lost segment


how can we know if a segment is lost or arrives out of order?

the simple answer is that every segment sent includes some notion of its place in the sequence of all segments

so, just as I’ve labeled the segments with monotonically-increasing numbers in all the diagrams above, the TCP metadata should include similar information

in the "segment is lost" ladder diagram above, when it receives segment 3, Process B says "hold on, I just received segment 1 and now I’m receiving segment 3, therefore segment 2 must have disappeared!"

the "segment arrives out of order" ladder diagram represents a similar situation: process B receives segment 2 first and concludes that it missed segment 1

the difference in this latter case is that segment 1 magically shows up shortly thereafter, whereas in the former case the missing segment does not

which means that, in the former case, Process B needs some way to tell Process A to re-send segment 2

alternatively, when it receives a segment, Process B could send back to Process A a message saying "I just received segment 1"

if Process A notices a gap in the acknowledgements, it can choose to re-send segments

for example: if Process A receives a segment from Process B saying "I just received segment 1" followed by another segment from Process B saying "I just received segment 3", then Process A could conclude that segment 2 was lost in transit, and choose to re-send just that segment


all of this leads to two medium-level ideas:

so the conversation is going to look (conceptually) more like this:

  Process A |   segment 1   | Process B
            | ------------> |
            |               |
            | ack segment 1 |
            | <------------ |
            |               |
            |   segment 2   |
            | ------------> |
            |               |
            | ack segment 2 |
            | <------------ |
            |               |
            |   segment 3   |
            | ------------> |
            |               |
            | ack segment 3 |
            | <------------ |
            |               |

the above diagram shows segments containing data flowing from A to B, and acknowledgements flowing from B to A

but TCP allows data to travel both directions, which means acknowledgements have to be able to travel in both directions as well

since one end of the connection may be way more talkative than the other, this leads to the idea that both directions use separate sets of sequence numbers

that is, segment 1 sent from A to B has no relation at all to segment 1 send from B to A

if A is really chatty, it could have sent segments 1 through 1000 before B even sends a segment 1 in the opposite direction


what happens if a segment doesn’t arrive? how does the system even know if a segment didn’t arrive?

  Process A |   segment 1   | Process B
            | ------------> |
            |               |
            | ack segment 1 |
            | <------------ |
            |               |
            |   segment 2   |
            | ----> X       |
            |               |
            |   segment 3   |
            | ------------> |
            |               |
            | ack segment 3 |
            | <------------ |
            |               |

in this example, Process B first notes and acknowledges the arrival of segment 1

and the next thing that arrives is segment 3, therefore it knows that segment 2 was lost

at which point it makes sense for Process B to ask Process A to re-send segment 2, the exact details of which we will deal with later, when we see exactly how these sequence numbers are realized


what if the very first segment is lost, though?

Process B doesn’t know it was supposed to receive anything at all, so it doesn’t know it should ask Process A to re-send

relatedly, what if Process A sends a segment but Process B doesn’t even exist?

it probably seems silly to allow Process A to send data before even verifying that anybody is around to receive it

and indeed this leads us to the idea of establishing a connection before actually sending application-level data over it

if we think back to the system calls that establish TCP connections, there are two: a client process uses connect(2) to establish a connection with a server process and a server process uses accept(2) to accept an incoming connection request from a client

the lower-level implication of these two syscalls is that connect(2) MUST NOT return until the server has confirmed creation of the connection and, similarly, accept(2) MUST NOT return until the client has confirmed creation of the connection

(this latter point may sound trivial, but it has consequences, which we will see soon)


conceptually, then, before sending any data, the two ends of the connection must agree that a connection exists between themselves and also inform the opposite end what sequence numbers to expect

thus, every TCP connection begins with an exchange of three packets

this is called the "TCP Three-Step Handshake"

remember that the purpose of accept(2) is to passively create connections: that is, to wait until somebody else comes knocking

on the opposite end, the purpose of connect(2) is to actively create a connection: it does that knocking

so if process B has called accept(2) and is awaiting an incoming connection request…

and process A calls connect(2) to create a connection to process B…

in ladder diagram form ("ISN" means "initial sequence number" and "ACK" means "acknowledge"):

  Process A |                               | Process B
            |                               |
            |                               | accept(2)
            |                               |
            |  ISN A to B                   |
  connect() | ----------------------------> |
            |                               |
            |  ACK(ISN A to B), ISN B to A  |
            | <---------------------------- |
            |                               |
            | ACK(ISN B to A)               |
            | ----------------------------> |
            |                               |

after having exchanged these three packets, both A and B know several things:


next time, we will look at how all this stuff is realized on the wire

because the details are, predictably, a bit more subtle and complex than I’ve presented today

Last modified: