CS144 lab2 笔记 📒
Lab Checkpoint 2: the TCP receiver
In Lab 2, you will implement the TCPReceiver, the part of a TCP implementation that handles the incoming byte stream. The
TCPReceivertranslates between incoming TCP segments (the payloads of datagrams carried over the Internet) and the incoming byte stream.
TCPReceiver除了写入即将到来的数据之外,还需要告诉发送端:
first_unassembled的索引(即ackno),是接收端当前所需要的第一个字节;first_unassembled和first unacceptable之间的距离(即window size)。
二者共同描述了接收端的窗口信息:「TCP 发送端允许发送的索引范围」:
\[ \left[ackno, ackno + window\ size \right) \]
3.1 Translating between 64-bit indexes and 32-bit seqnos
Lab1
中实现的StreamReassembler能够重组数据流字符串(64-bit
indexes)。可以认为 64-bit index
足够大到不可能溢出。[1]而在
TCP 首部,由于空间非常宝贵,数据流的每个字节的索引即"sequence
number"/"seqno."以 32-bit 呈现。以下 3 点需要注意:
- 实现需要考虑包装 32-bit 整型。\(2^{32}\) bytes 只有 \(4\) GiB,需要循环计数(\(0\ \sim \ 2^{32}-1\));
- TCP sequence numbers 起始于一个随机数。为了提高安全性和避免不同连接之间的混淆,TCP 试图确保序列号不能被猜到,而且不太可能重复。因此,一个流的序列号不从零开始。流中的第一个序列号通常是一个随机的 32-bit 整型,称为初始序列号(ISN)。这是代表 SYN(流的开始)的序列号。数据的第一个 byte 的序列号将会是\(\rm{ISN} + 1(\rm{mod}\ 2^{32})\);
- 开始和结束都算作序列中的一个位置。除了确保收到所有字节的数据外,TCP 必须确保也能收到流的开始和结束。因此,在 TCP 中,SYN(数据流的开始)和 FIN(数据流的结束)标志都被分配了序列号。这些计数都在序列中占据一个位置。数据流中的每个字节也在序列中占据一个位置。
下面是cat字符串的例子,其中ISN = \(2^{32}-2\)
\[ \begin{array}{r|c|c|c|c|c} \text { element } & \text { SYN } & \text { c } & \text { a } & \text { t } & \text { FIN } \\ \hline \text { seqno } & 2^{32}-2 & 2^{32}-1 & 0 & 1 & 2 \\ \hline \text { absolute seqno } & 0 & 1 & 2 & 3 & 4 \\ \hline \text { stream index } & & 0 & 1 & 2 & \end{array} \]
TCP 涉及到的三种不同索引方式如下表所示
| Sequence Numbers | Absolute Sequence Numbers | Stream Indices |
|---|---|---|
| Start at the ISN | Start at 0 | Start at 0 |
| Include SYN/FIN | Include SYN/FIN | Omit SYN/FIN |
| 32 bits, wrapping | 64 bits, non-wrapping | 64 bits, non-wrapping |
| “seqno” | “absolute seqno” | “stream index” |
实现前两者的相互转换将通过以下两个函数:
WrappingInt32 wrap(uint64_t n, WrappingInt32 isn):absolute seqno. \(\rightarrow\) seqno.uint64_t unwrap(WrappingInt32 n, WrappingInt32 isn, uint64_t checkpoint):seqno. \(\rightarrow\) absolute seqno. 其中checkpoint用于消除 absolute seqno 的歧义,最接近 checkpoint 的对应 absolute seqno. 即为所求。(checkpoint表示最近一次转换求得的absolute seqno,而本次转换出的absolute seqno应该选择与上次值最为接近的那一个)
1 | |
3.1 Implementing the TCP receiver
将实现TCPReceiver。它将
- 从它的对等方接收 segments;
使用
StreamReassembler重新组装ByteStream维护确认号(ackno) 和 窗口大小。

需要注意的是 ackno 的更新,因为 TCPsegment 的传入可能是乱序的,同时 SYN 和 FIN 也影响着 ackno,还要考虑可能同时到达的情况。
window_size实质上是接收者能够接受的索引范围大小。也就是first unassembled和first unacceptable之间的距离。In other words: it's the capacity minus the number of bytes that the TCPReceiver is holding in the byte stream.
1 | |
1 | |
更新:将第 27 行代码更新为第 28 行代码 修复了下述情况遇到的错误
1 | |
| seqno | 2303251161 | 2303251162 | 2303251163 | 2303251164 | 2303251165 | 2303251166 | 2303251167 | 2303251168 | 2303251169 |
|---|---|---|---|---|---|---|---|---|---|
| e | |||||||||
| g | |||||||||
| c | |||||||||
| a | b | ||||||||
| f | |||||||||
- 添加
_first_unassembled的接口 - 修复了上述 bug
参考
- 以 100Gbps 的传输速度计算,需要接近 50 年的时间才能达到 (2^{64}) bytes 的数据量;作为对比,只需要约 (1/3) 秒即可达到 (2^{32}) bytes 的数据量。 ↩︎