CS144-check2

overview

这个lab需要我们实现TCP协议中的接收方,具体的,负责实现确认(acknowledgement)和流控制(flow control)。

64bit index - 32bit seqno

第一个部分,需要我们实现将上一个lab里面stream的index转换为TCP报文的序列号,指导书给出了序列号的特点:

  • 序列号只有32位,属于阿贝尔群
  • 序列号并不一定从0开始,可以是随机数。第一个序列号被称为ISN(initial sequence number)。
  • 对于每个stream,在其前面的SYN flag和FIN flag也是需要使用序列号的。

为了方便,我们定义了64位绝对序列号,第一个序列号对应到绝对序列号为0,以此类推。而对于一个stream,其index就等于绝对序列号-1(SYN占据了0的位置)。

  • wrap实现了绝对序列号到序列号的转换
  • unwrap实现了序列号到绝对序列号的转换

因为序列号可能对应多个绝对序列号,所以需要找到离checkpoint最近的绝对序列号,每个比较都是采用绝对值,是为了防止边界情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Wrap32 Wrap32::wrap( uint64_t n, Wrap32 zero_point )
{
return zero_point + static_cast<uint32_t>(n);
}

uint64_t Wrap32::unwrap( Wrap32 zero_point, uint64_t checkpoint ) const
{
uint64_t offset = static_cast<uint64_t>(raw_value_ - zero_point.raw_value_);
uint64_t t = offset + (checkpoint & 0xffffffff00000000);
uint64_t dis1 = (t + (1UL << 32) > checkpoint) ? (t + (1UL << 32) - checkpoint) : (checkpoint - t - (1UL << 32));
uint64_t dis2 = (t > checkpoint) ? (t - checkpoint) : (checkpoint - t);
uint64_t dis3 = (t - (1UL << 32) > checkpoint) ? (t - (1UL << 32) - checkpoint) : (checkpoint - t + (1UL << 32));
uint64_t ans;
if(dis1 < dis2){
if(dis1 < dis3)
ans = t + (1UL << 32);
else
ans = t - (1UL << 32);
} else {
if(dis2 < dis3)
ans = t;
else
ans = t - (1UL << 32);
}
return ans;
}

TCP receiver

这里需要我们正式开始实现接收方的动作。先把类中的成员丢在这里,下面解释。

1
2
3
4
5
6
7
8
9
class TCPReceiver
{
...
private:
Reassembler reassembler_;
Wrap32 ISN {0};
bool ISN_recv {false};
uint64_t ack_abseqno {};
};

指导书上只是讲了一些原理,但有一些东西没讲清楚。

  • 要注意我们需要发送的ackno是根据已接收并且已经按顺序排好的字节来设定的,需要使用first_unassemble_byte的位置来确定。
  • 特别注意,每个stream都有一对SYN和FIN,都占序列号,不要忘记将他们加到ackno里面。

其他的实现要素在指导书上都有,多读几遍,多看调试的信息就可以知道程序的行为了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
void TCPReceiver::receive( TCPSenderMessage message )
{
if(message.RST){
reassembler_.reader().set_error();
return;
}

if(message.SYN){
ISN = message.seqno;
ISN_recv = true;
reassembler_.insert(0, message.payload, message.FIN);
ack_abseqno += message.sequence_length();
return;
}

if(!ISN_recv)
return;


uint64_t first_unindex = reassembler_.writer().bytes_pushed();
reassembler_.insert(message.seqno.unwrap(ISN, first_unindex)-1, message.payload, message.FIN);
ack_abseqno = reassembler_.writer().bytes_pushed() + 1;
if(reassembler_.writer().is_closed())
ack_abseqno += 1;
}


TCPReceiverMessage TCPReceiver::send() const
{
TCPReceiverMessage t;
if(ISN_recv){
t.ackno = Wrap32::wrap(ack_abseqno, ISN);
}

if(reassembler_.reader().has_error())
t.RST = true;

t.window_size = (reassembler_.writer().available_capacity() > UINT16_MAX) ? UINT16_MAX : reassembler_.writer().available_capacity();
return t;
}

CS144-check2
https://pactheman123.github.io/2024/09/19/CS144-check2/
作者
Xiaopac
发布于
2024年9月19日
许可协议