关于c++:CS144-Lab-Assignments-手写TCP-LAB2

38次阅读

共计 3228 个字符,预计需要花费 9 分钟才能阅读完成。

CS 144: Introduction to Computer Networking, Fall 2020
https://cs144.github.io/

My Repo
https://github.com/wine99/cs1…

Translating between 64-bit indexes and 32-bit seqnos

留神 wrapping_integers.hh 中的这三个办法:

inline int32_t operator-(WrappingInt32 a, WrappingInt32 b) {return a.raw_value() - b.raw_value();}

//! \brief The point `b` steps past `a`.
inline WrappingInt32 operator+(WrappingInt32 a, uint32_t b) {return WrappingInt32{a.raw_value() + b}; }

//! \brief The point `b` steps before `a`.
inline WrappingInt32 operator-(WrappingInt32 a, uint32_t b) {return a + -b;}

上面的两个加减,别离是在 WrappingInt32 上加上或减去一个 uint32_t,失去的后果依然是一个 WrappingInt32,其意义是别离为把 a 这个 WrappingInt32 向前或向后挪动 |b| 个单位间隔。

而第一个减法重载,是两个 WrappingInt32 相减,失去的是一个 int32_t,要想了解其意义,首先要弄懂上面的代码:

// 2 ^ 32 = 4294967296

uint32_t a = 1;
uint32_t b = 0;
uint32_t x = a - b;
int32_t  y = a - b;
// x=1 y=1
uint32_t x = b - a;
int32_t  y = b - a;
// x=4294967295 y=-1

uint32_t a = 1;
uint32_t b = static_cast<uint32_t>((1UL << 32) - 1UL);
uint32_t x = a - b;
int32_t  y = a - b;
// x=2 y=2
uint32_t x = b - a;
int32_t  y = b - a;
// x=4294967294 y=-2

下面的运算阐明:c(int32_t) = a(uint32_t) - b(uint32_t) 的 c 的绝对值的意义是从 b 走到 a 须要破费的起码步数,如果 c 是负数,则向数轴的正方向走,否则向反方向走。之所以存在最小步数一说,是因为往反方向走穿梭 0 会到 2^32 – 1,往正方向走穿梭 2^32 – 1 会回到 0。这个步数也肯定不会超过 2^31 步。第一个减法也是这样的意义,代表了从 WrappingInt32 b 走到 WrappingInt32 a 起码须要的步数。

了解了这三个运算符重载后,就能够编写 Wrapping_integers.cc 了:

WrappingInt32 wrap(uint64_t n, WrappingInt32 isn) {return isn + static_cast<uint32_t>(n); }

uint64_t unwrap(WrappingInt32 n, WrappingInt32 isn, uint64_t checkpoint) {
    // STEP ranges from -UINT32_MAX/2 to UINT32_MAX/2
    // in most cases, just adding STEP to CHECKPOINT will get the absolute seq
    // but if after adding, the absolute seq is negative, it should add another (1UL << 32)
    // (this means the checkpoint is near 0 so the new seq should always go bigger
    // eg. test/unwrap.cc line 25)
    int32_t steps = n - wrap(checkpoint, isn);
    int64_t res = checkpoint + steps;
    return res >= 0 ? checkpoint + steps : res + (1UL << 32);
}

首先看把 64 位的 index 转换为 WrappingInt32 的 wrap 函数。依据下面的表格,显然,只须要利用加法重载,把 ISN 往前走 n(=index) 步就能够了。

而后看 unwrap 函数,起作用是把新接管到的报文段的 seqno(WrappingInt32)转换为 64 位的 index。seqno 转 index 的后果显然不惟一,咱们想要的是与上一次收到的报文段的 index(checkpoint)最靠近的那个转换后果。于是,能够先用刚写好的 wrap 函数把 checkpoint 变为 WrappingInt32,而后利用第一个减法重载,找出这个转换后的 seqno 起码须要走几步能够到新报文的 seqno,而后把这个步数加到 checkpoint 上。留神这里有一个非凡状况(见代码正文),因为咱们有可能是往数轴的反方向走的,可能走完之后 res 的值是个正数,这时候须要在加上一个 2^32。

Implementing the TCP receiver

留神测试外面的非凡状况,例如

  • SYN with DATA
  • SYN with DATA with FIN
  • SYN + FIN
  • SYN + DATA with FIN + DATA

而后依据未通过的测试,一步步欠缺逻辑,测试全副通过后再从新简化代码,最终失去解法如下(局部思路见正文):

void TCPReceiver::segment_received(const TCPSegment &seg) {TCPHeader header = seg.header();
    if (header.syn && _syn)
        return;
    if (header.syn) {
        _syn = true;
        _isn = header.seqno.raw_value();}
    // note that fin flag seg can carry payload
    if (_syn && header.fin)
        _fin = true;
    size_t absolute_seqno = unwrap(header.seqno, WrappingInt32(_isn), _checkpoint);
    _reassembler.push_substring(seg.payload().copy(), header.syn ? 0 : absolute_seqno - 1, header.fin);
    _checkpoint = absolute_seqno;
}

optional<WrappingInt32> TCPReceiver::ackno() const {// Return the corresponding 32bit seqno of _reassembler.first_unassembled().
    // Translate from Stream Index to Absolute Sequence Number is simple, just add 1.
    // If outgoing ack is corresponding to FIN
    // (meaning FIN is received and all segs are assembled),
    // add another 1.
    size_t shift = 1;
    if (_fin && _reassembler.unassembled_bytes() == 0)
        shift = 2;
    if (_syn)
        return wrap(_reassembler.first_unassembled() + shift, WrappingInt32(_isn));
    return {};}

size_t TCPReceiver::window_size() const {
    // equal to first_unacceptable - first_unassembled
    return _capacity - stream_out().buffer_size();
}

正文完
 0