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 unassembledfirst 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.
  • 实现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
  • 实现TCP receiver

    • lab中会用到TCPSegment类,它的length in sequence space()方法会很有用,用来计算在该TCPSegment中有多少序列号,SYN与FIN也会占据一个序列号;以及TCPHeader类

    • 需要实现三个方法,segment received(), ackno(), window size()

    • std::optional ackno() const;用到了CPP17新特性optional, 可以参考,大概就是说可以更优雅的处理空值的情况,通过返回nullopt,另外为了解决编译器报错,做以下修改

    • 实现

      • TCPreceiver将接收到的TCPsegment做处理,讲有效的字节序列放入StreamReassembler中,当然需要对TCPsegmen做相应处理,
      • 实际上,StreamReassembler中的ByteStream就是TCPreceiver的缓存,StreamReassembler起到一个中间处理的作用,ByteStream是实际缓存,那么三者的capacity是一致的
    • 实现中遇到的问题

      • 本来没看懂lab要我做什么,就想着去看别人的,看了好几个都好长,好难懂,就自己写了;SYN占一个序列号,虽然文档中强调了,由于_isn设置为了syn的序列号,那么获取当前序列号对应的absolute sequno,hdr.seqno + (hdr.syn ? 1 : 0)表示syn占据了一个序列号
      • 对于_fin的置位,需要fin置位的TCPsegment收到了,且没有因为窗口大小问题被丢弃;并且只有当_fin置位,字节流的中所有的字节都被push了,那么才需要考虑fin占据了一个序列号

ASAP是as soon as possible