WrappingInt32 wrap(uint64_t n, WrappingInt32 isn){ return isn + uint32_t(n); }
//! Transform a WrappingInt32 into an "absolute" 64-bit sequence number (zero-indexed) //! \param n The relative sequence number //! \param isn The initial sequence number //! \param checkpoint A recent absolute 64-bit sequence number //! \returns the 64-bit sequence number that wraps to `n` and is closest to `checkpoint` //! //! \note Each of the two streams of the TCP connection has its own ISN. One stream //! runs from the local TCPSender to the remote TCPReceiver and has one ISN, //! and the other stream runs from the remote TCPSender to the local TCPReceiver and //! has a different ISN. uint64_tunwrap(WrappingInt32 n, WrappingInt32 isn, uint64_t checkpoint){ uint64_t u64_left = 0, u64_right = 0; // 计算基础偏移 if(n - isn < 0) { // u32 已经循环 // 得到绝对序列号的低32位 u64_right = uint64_t(n - isn + (1l << 32)); } else { u64_right = uint64_t(n - isn); } if(u64_right >= checkpoint) { // 其他候选值都会更大,目前最接近 return u64_right; } // 将 u64_right 的高32位设置为与检查点的高32位相同,低32位保持不变(即基础偏移) u64_right |= ((checkpoint >> 32) << 32); // 寻找第一个大于 checkpoint 的候选值 while(u64_right <= checkpoint) { u64_right += (1ll << 32); } // 小于或等于 checkpoint 的最后一个候选值 u64_left = u64_right - (1ll << 32); // 选择距离 checkpoint 最近的 return (checkpoint - u64_left < u64_right - checkpoint) ? u64_left : u64_right; }
实现
主要需要实现 segment_received、ackno 和 window_size 方法。
classTCPReceiver { //! Our data structure for re-assembling bytes. StreamReassembler _reassembler;
//! The maximum number of bytes we'll store. size_t _capacity;
//! Flag to indicate whether the first SYN message has received bool _synReceived;
//! Flag to indicate whether FIN mesaage has received bool _finReceived;
//! Inital Squence Number WrappingInt32 _isn;
public: //! \brief Construct a TCP receiver //! //! \param capacity the maximum number of bytes that the receiver will //! store in its buffers at any give time. TCPReceiver(constsize_t capacity) : _reassembler(capacity), _capacity(capacity), _synReceived(false), _finReceived(false), _isn(0) {}
//! \name Accessors to provide feedback to the remote TCPSender //!@{
//! \brief The ackno that should be sent to the peer //! \returns empty if no SYN has been received //! //! This is the beginning of the receiver's window, or in other words, the sequence number //! of the first byte in the stream that the receiver hasn't received. std::optional<WrappingInt32> ackno()const;
//! \brief The window size that should be sent to the peer //! //! Operationally: the capacity minus the number of bytes that the //! TCPReceiver is holding in its byte stream (those that have been //! reassembled, but not consumed). //! //! Formally: the difference between (a) the sequence number of //! the first byte that falls after the window (and will not be //! accepted by the receiver) and (b) the sequence number of the //! beginning of the window (the ackno). size_twindow_size()const; //!@}
//! \brief number of bytes stored but not yet reassembled size_tunassembled_bytes()const{ return _reassembler.unassembled_bytes(); }
//! \brief handle an inbound segment voidsegment_received(const TCPSegment &seg);