1.如果 ackno_64大于 _next_seqno,就会触发SYN_SENT状态,按照常理来说,ackno_64是不应该大于 _next_seqno,如果ackno_64大于 _next_seqno,我们将其定为“stream started but nothing acknowledged“,直接返回即可,等待下一次传入的ackno,至于为什么会出现ackno_64大于 _next_seqno我们并不关心。代码如下:
//! \brief The "sender" part of a TCP implementation.
//! Accepts a ByteStream, divides it up into segments and sends the //! segments, keeps track of which segments are still in-flight, //! maintains the Retransmission Timer, and retransmits in-flight //! segments if the retransmission timer expires. classTCPSender { private: //! our initial sequence number, the number for our SYN. WrappingInt32 _isn;
uint64_t base{0};
//! outbound queue of segments that the TCPSender wants sent std::queue<TCPSegment> _segments_out{}; std::queue<TCPSegment> _segments_out_cache{}; //! retransmission timer for the connection unsignedint _initial_retransmission_timeout;
//! outgoing stream of bytes that have not yet been sent ByteStream _stream;
//! the (absolute) sequence number for the next byte to be sent uint64_t _next_seqno{0}; uint16_t curr_window_size; bool fin_flag; size_t _total_time; bool time_waiting; int _consecutive_remission; size_t _time_out; bool window_zero; public: //! Initialize a TCPSender TCPSender(constsize_t capacity = TCPConfig::DEFAULT_CAPACITY, constuint16_t retx_timeout = TCPConfig::TIMEOUT_DFLT, const std::optional<WrappingInt32> fixed_isn = {});
//! \name "Input" interface for the writer //!@{ ByteStream &stream_in(){ return _stream; } const ByteStream &stream_in()const{ return _stream; } //!@}
//! \name Methods that can cause the TCPSender to send a segment //!@{
//! \brief A new acknowledgment was received voidack_received(const WrappingInt32 ackno, constuint16_t window_size);
//! \brief Generate an empty-payload segment (useful for creating empty ACK segments) voidsend_empty_segment();
//! \brief create and send segments to fill as much of the window as possible voidfill_window();
//! \brief Notifies the TCPSender of the passage of time voidtick(constsize_t ms_since_last_tick); //!@}
//! \name Accessors //!@{
//! \brief How many sequence numbers are occupied by segments sent but not yet acknowledged? //! \note count is in "sequence space," i.e. SYN and FIN each count for one byte //! (see TCPSegment::length_in_sequence_space()) size_tbytes_in_flight()const;
//! \brief Number of consecutive retransmissions that have occurred in a row //连续发生的重传次数 unsignedintconsecutive_retransmissions()const;
//! \brief TCPSegments that the TCPSender has enqueued for transmission. //! \note These must be dequeued and sent by the TCPConnection, //! which will need to fill in the fields that are set by the TCPReceiver //! (ackno and window size) before sending. std::queue<TCPSegment> &segments_out(){ return _segments_out; } //!@}
//! \name What is the next sequence number? (used for testing) //!@{
//! \brief absolute seqno for the next byte to be sent uint64_tnext_seqno_absolute()const{ return _next_seqno; }
//! \brief relative seqno for the next byte to be sent WrappingInt32 next_seqno()const{ returnwrap(_next_seqno, _isn); } //!@} };
//! \param[in] capacity the capacity of the outgoing byte stream //! \param[in] retx_timeout the initial amount of time to wait before retransmitting the oldest outstanding segment //! \param[in] fixed_isn the Initial Sequence Number to use, if set (otherwise uses a random ISN) TCPSender::TCPSender(constsize_t capacity, constuint16_t retx_timeout, const std::optional<WrappingInt32> fixed_isn) : _isn(fixed_isn.value_or(WrappingInt32{random_device()()})) ,base(0) , _initial_retransmission_timeout{retx_timeout} , _stream(capacity) , curr_window_size(1) , fin_flag(false) , _total_time(0) , time_waiting(false) , _consecutive_remission(0) , _time_out(0) , window_zero(false) {
//! \param[in] ms_since_last_tick the number of milliseconds since the last call to this method voidTCPSender::tick(constsize_t ms_since_last_tick){ DUMMY_CODE(ms_since_last_tick); _total_time+=ms_since_last_tick; //如果缓冲队列不为空,停等时间在运行,且总时间大于超时 if(!_segments_out_cache.empty()&&time_waiting&&_total_time>=_time_out){ _segments_out.push(_segments_out_cache.front()); //重传次数增加 _consecutive_remission++; if(!window_zero){ _time_out*=2; } _total_time=0; } }