Standford CS144 lab2
Lab2 the TCP receiver
-
总览
- 这次实验要实现TCP receiver,它将
TCP segments
转换为字节流
- TCP receiver 通过segment received() 方法接收segments
- TCP receiver还需要告知
发送方
确认号ackno
,也就是第一个unassembled 的字节号,ackno
又称为left edge
, 而ackno + windowsize
又称为right edge
- TCP receiver 还需要告诉
发送方
接收窗口大小window size
,也就是first unassembled
和first unacceptable
之间的大小 接收窗口window size
可以使发送方实现流量控制- 这个lab最难的部分
The hardest part will involve thinking about how TCP will represent each byte’s place in the stream—known as a “sequence number.
- 这次实验要实现TCP receiver,它将
-
实现64-bit的字节流下标与32-bit的序列号之间的转换
- 在lab1中实现的字节流重组器的字节有64bit的流下标,64bit的下标可以看成无限大
Transmitting at 100 gigabits/sec, it would take almost 50 years to reach 2^64 bytes. By contrast, it takes only a third of a second to reach 2^32 bytes.
但是TCP头部的序列号
只有32个字节大小,所以需要转换 - 序列号2^32 - 1下一个就是0
- 为了提高安全性与避免过期的报文与当前报文产生冲突,TCP 序列号开始于一个随机的值,它被叫做
Initial Sequence Number (ISN)
,该序列号用于SYN,也就是建立连接 SYN
需要占一个序列号,而FIN
也需要占一个序列号,SYN
表示字节流的开始,FIN
表示字节流的结束- 接收方与发送方两端都有一个字节流,都有一个
random ISN
- 之后会提及
absolute sequence number
,也就是不会绕回的序列号,与stream index
的概念,也就是字节流的下标,对于一个
- 在这个lab中,序列号是一个定制化的类型
WrapppingInt32
,也就是uint32_t加上一些函数与操作符,而绝对序列号
用uint64_t表示 - 需要实现一个wrap函数,用于
绝对序列号
到序列号
的转换 - 需要实现一个unwrap函数,用于用于
序列号
到绝对序列号
的转换,一个序列号可能对应多个绝对序列号,比如ISN是0,而序列号为17,可以对应绝对序列号2^32 + 17, 2 ^ 33 + 17等,可以通过把the last reassembled byte
作为衡量点(checkpoint)来解决该问题,并且lab提供了帮助函数,在TCP实现中,the last reassembled byte充当checkpoint
- 在lab1中实现的字节流重组器的字节有64bit的流下标,64bit的下标可以看成无限大
-
实现TCP receiver
-
lab中会用到TCPSegment类,它的length in sequence space()方法会很有用,用来计算在该TCPSegment中有多少序列号,SYN与FIN也会占据一个序列号;以及TCPHeader类
-
需要实现三个方法,
segment received()
,ackno()
,window size()
-
std::optional
用到了CPP17新特性optional, 可以参考,大概就是说可以更优雅的处理空值的情况,通过返回nullopt,另外为了解决编译器报错,做以下修改ackno() const;
-
实现
- TCPreceiver将接收到的TCPsegment做处理,讲有效的字节序列放入
StreamReassembler
中,当然需要对TCPsegmen做相应处理, - 实际上,
StreamReassembler
中的ByteStream
就是TCPreceiver的缓存,StreamReassembler
起到一个中间处理的作用,ByteStream
是实际缓存,那么三者的capacity是一致的
- TCPreceiver将接收到的TCPsegment做处理,讲有效的字节序列放入
-
实现中遇到的问题
- 本来没看懂lab要我做什么,就想着去看别人的,看了好几个都好长,好难懂,就自己写了;SYN占一个序列号,虽然文档中强调了,由于_isn设置为了syn的序列号,那么获取当前序列号对应的absolute sequno,
hdr.seqno + (hdr.syn ? 1 : 0)
表示syn占据了一个序列号 - 对于_fin的置位,需要fin置位的TCPsegment收到了,且没有因为窗口大小问题被丢弃;并且只有当_fin置位,字节流的中所有的字节都被push了,那么才需要考虑fin占据了一个序列号
- 本来没看懂lab要我做什么,就想着去看别人的,看了好几个都好长,好难懂,就自己写了;SYN占一个序列号,虽然文档中强调了,由于_isn设置为了syn的序列号,那么获取当前序列号对应的absolute sequno,
-
ASAP是as soon as possible