Abstact
前面两次实验分别实现了一个字节流抽象和一个字节流重装器,本次实验将开始深入TCP细节之中:实现一个 TCPReceiver,从对端Sender中接收字节流并发给Reassembler进行重组,以及将ackno和 window size发回给对端的Sender
Translating between 64-bit indexes and 32-bit seqnos
基于初始序列化(ISN/zero_point)将uint64_t
类型的绝对序列号转为uint32_t
类型的(相对)序列号
Wrap32 Wrap32::wrap( uint64_t n, Wrap32 zero_point )
{
// uint64_t -> uint32_t <==> val_u64 % 2^32
return zero_point + static_cast<uint32_t>(n);
}
基于初始序列化(ISN/zero_point)和checkpoint(接近绝对序列号的一个参考值),将uint32_t
类型的相对序列号转为 uint64_t
类型的绝对序列号
uint64_t Wrap32::unwrap( Wrap32 zero_point, uint64_t checkpoint ) const
{
Wrap32 cp = wrap( checkpoint, zero_point );
int32_t offset = raw_value_ - cp.raw_value_;
int64_t res = checkpoint + offset;
return res >= 0 ? res : res + ( 1ul << 32 );
}
Implementing the TCP receiver
TCP receiver 包含void receive( TCPSenderMessage message );
和 TCPReceiverMessage send() const;
两个需要实现的接口
receive()
: 从对端的TCPSender中接收Message(包括seqno、SYN flag、payload、FIN flag和RST flag),计算绝对序列号(stream_index),并将payload插入到Reassembler中
void TCPReceiver::receive( TCPSenderMessage message )
{
if (writer().has_error() || message.RST) {
if (message.RST) {
reader().set_error();
}
return;
}
if ( not isn_.has_value() ) {
if (not message.SYN) {
return;
}
isn_ = message.seqno;
}
uint64_t checkpoint = writer().bytes_pushed() + 1; // added SYN
uint64_t abs_seqno = message.seqno.unwrap( isn_.value(), checkpoint );
// 为什么要 + message.SYN?
// 考虑 SYN + FIN 的字节流,FIN 标记应该在字节流的末尾,确保了即使没有数据 FIN 也能正确标记流的结束
uint64_t stream_index = abs_seqno + static_cast<uint64_t>( message.SYN ) - 1;
reassembler_.insert( stream_index, message.payload, message.FIN );
}
send()
: 根据abs_seqno计算ackno,根据available_capacity()计算window_size,从而构造一个 TCPReceiverMessage
TCPReceiverMessage TCPReceiver::send() const
{
TCPReceiverMessage msg;
if ( isn_.has_value() ) {
uint64_t abs_seqno = writer().bytes_pushed();
if ( writer().is_closed() ) {
abs_seqno += 2; // 1 byte for FIN
} else {
abs_seqno += 1;
}
msg.ackno = Wrap32::wrap( abs_seqno, isn_.value() );
}
msg.window_size = writer().available_capacity() <= UINT16_MAX ?
writer().available_capacity() : UINT16_MAX;
msg.RST = writer().has_error();
return msg;
}
Leave a Reply