Here are the basic rules the TCPConnection has to follow:
Receiving segments
大概是在segment_received中做
检查RST flag
如果RST被设置,sets both the inbound and outbound streams to the error state,杀死当前connection
return;
具体实现中,杀死connection可以置_linger_after_streams_finish为false。 the inbound and outbound streams对应着receiver和sender里的stream。让它们都处于error状态,只需设置ByteStream中的error字段
如果收到的segment with an invalid sequence number,connection需要发送empty segment应答
//! outbound queue of segments that the TCPConnection wants sent // 把要发送的segment放在这里就行了 std::queue<TCPSegment> _segments_out{};
//! Should the TCPConnection stay active (and keep ACKing) //! for 10 * _cfg.rt_timeout milliseconds after both streams have ended, //! in case the remote TCPConnection doesn't know we've received its whole stream? bool _linger_after_streams_finish{true};
public: // 也许需要调用TCPSender的fill_window(),然后从其segment_out中取出来,再发送给自己的segment_out // Initiate a connection by sending a SYN segment初始化connection并且发送SYN voidconnect();
/* 这几个都很好实现,都很直观,只需调sender和receiver的API就行 */ // 由上层socket调用,data路径 socket->connection->sender.stream_in().write() //! \brief Write data to the outbound byte stream, and send it over TCP if possible //! \returns the number of bytes from `data` that were actually written. size_twrite(const std::string &data); //! \returns the number of `bytes` that can be written right now. size_tremaining_outbound_capacity()const; //! \brief Shut down the outbound byte stream (still allows reading incoming data) voidend_input_stream(); //! \brief The inbound byte stream received from the peer ByteStream &inbound_stream(){ return _receiver.stream_out(); } // number of bytes sent and not yet acknowledged, counting SYN/FIN each as one byte size_tbytes_in_flight()const; //! \brief number of bytes not yet reassembled size_tunassembled_bytes()const;
//! \brief Number of milliseconds since the last segment was received size_ttime_since_last_segment_received()const;
// debug用 //!< \brief summarize the state of the sender, receiver, and the connection TCPState state()const{ return {_sender, _receiver, active(), _linger_after_streams_finish}; };
// 这些函数都会由上层在某些时候调用 // 时钟滴答、收到segment以及从segment_out中取数据,这些都是由os调用相应函数实现的 // 这也正是所谓“协议”的接口意义! //! \name Methods for the owner or operating system to call //! Called when a new segment has been received from the network voidsegment_received(const TCPSegment &seg);
//! Called periodically when time elapses voidtick(constsize_t ms_since_last_tick);
//! \brief TCPSegments that the TCPConnection has enqueued for transmission. //! \note The owner or operating system will dequeue these and //! put each one into the payload of a lower-layer datagram (usually Internet datagrams (IP), //! but could also be user datagrams (UDP) or any other kind). std::queue<TCPSegment> &segments_out(){ return _segments_out; }
//! \brief Is the connection still alive in any way? //! \returns `true` if either stream is still running or if the TCPConnection is lingering //! after both streams have finished (e.g. to ACK retransmissions from the peer) boolactive()const;
//! Construct a new connection from a configuration explicitTCPConnection(const TCPConfig &cfg) : _cfg{cfg} {}
//! \name construction and destruction //! moving is allowed; copying is disallowed; default construction not possible
~TCPConnection(); //!< destructor sends a RST if the connection is still open TCPConnection() = delete; TCPConnection(TCPConnection &&other) = default; TCPConnection &operator=(TCPConnection &&other) = default; TCPConnection(const TCPConnection &other) = delete; TCPConnection &operator=(const TCPConnection &other) = delete;
// in libsponge/tcp_helper/tcp_sponge_socket.cc _initialize_TCP() // Set up the event loop
// There are four possible events to handle: // // 1) Incoming datagram received (needs to be given to // TCPConnection::segment_received method) // // 2) Outbound bytes received from local application via a write() // call (needs to be read from the local stream socket and // given to TCPConnection::data_written method) // // 3) Incoming bytes reassembled by the TCPConnection // (needs to be read from the inbound_stream and written // to the local stream socket back to the application) // // 4) Outbound segment generated by TCP (needs to be // given to underlying datagram socket)
// ms_since_last_tick: number of milliseconds since the last call to this method voidTCPConnection::tick(constsize_t ms_since_last_tick){ ticks += ms_since_last_tick; _sender.tick(ms_since_last_tick); if (_sender.consecutive_retransmissions() > _cfg.MAX_RETX_ATTEMPTS) { while (!_sender.segments_out().empty()) _sender.segments_out().pop(); // 清除sender遗留的所有帧 _sender.send_empty_rst_segment();// 只发送rst帧 set_rst(); } segment_send(); // end the connection cleanly if necessary if (_receiver.stream_out().input_ended() && _sender.stream_in().eof() && _sender.bytes_in_flight() == 0 && _sender.fully_acked() && time_since_last_segment_received() >= 10 * _cfg.rt_timeout) { // 等待结束 _linger_after_streams_finish = false; }