Every time a segment containing data (nonzero length in sequence space) is sent (whether it’s the first time or a retransmission), if the timer is not running, start itrunning so that it will expire after RTO milliseconds.
// 尽可能地创造segment并且填充到segment output中 voidTCPSender::fill_window(){ // should act like the window size is one size_t t_win_size = window_size == 0 ? 1 : window_size; size_t remaining = t_win_size - tmp_size; // 防止数值溢出的情况 if (t_win_size < tmp_size) remaining = 0;
// fill as possible while (remaining > 0) { // create and fill in a segment TCPSegment segment = TCPSegment(); // 如果处于CLOSED状态 if (!syn) { // 转移到SYN_SENT状态 // first segment segment.header().syn = true; segment.header().seqno = _isn; remaining -= 1; syn = true; // should start the timer here rto = _initial_retransmission_timeout; timer_start = true; timer_ticks = ticks; } // fill in the payload if (!segment.header().syn && !(_stream.buffer_empty() || remaining == 0)) { string data = _stream.read(min(remaining, TCPConfig::MAX_PAYLOAD_SIZE)); remaining -= data.length(); Buffer buf = Buffer(move(data)); segment.payload() = buf; }
// 转移到FIN_SENT状态 if (_stream.eof() && !fin && remaining > 0) { // last segment segment.header().fin = true; fin = true; remaining -= 1; }
// segment为空(不为SYN、FIN,也不携带任何数据) if (segment.length_in_sequence_space() == 0) break;
segment.header().seqno = wrap(_next_seqno, _isn); _next_seqno += segment.length_in_sequence_space(); // push into the outstanding segments tmp_segments.push_back( {segment, unwrap(segment.header().seqno, _isn, _next_seqno), segment.length_in_sequence_space()}); tmp_size += segment.length_in_sequence_space(); // push into the segment out queue _segments_out.push(segment); } }
voidTCPSender::ack_received(const WrappingInt32 ack, constuint16_t wind_size){ window_size = wind_size; uint64_t a_ack = unwrap(ack, _isn, ackno); if (a_ack > _next_seqno) return; // impossible ack is ignored if (a_ack > ackno) { // reset the retransmission rto = _initial_retransmission_timeout; timer_ticks = ticks; cons_retran = 0; // erase elements from the tmp_segments for (auto it = tmp_segments.begin(); it != tmp_segments.end();) { if (a_ack >= it->seqno + it->data_size) { tmp_size -= (it->segment).length_in_sequence_space(); // 如果FIN报文被成功接收,就关闭timer // FIN_ACKED if (it->segment.header().fin) timer_start = false; it = tmp_segments.erase(it); } else it++; } } ackno = a_ack; fill_window(); }