Stanford CS144 Lab.TCP Connection
于2022年4月20日2022年4月20日由Sukuna发布
在这里我们需要实现一个TCP连接类,在这个TCP连接类里面,我们需要组合之前已经写好的TCP发送端和接收端的函数来进行处理.
1、接受到segment的操作:
分成两种操作,一种是正常的交互,一种是握手的操作.握手又分成主动请求链接和被动链接,在这两种模式下接受握手信息的处理是不一样的.对于正常的交互,需要交付给Sender和Reciever.因为对于TCP来说,两者是相互统一的.两个主机之间也会互相传递信息,所以说交给发送端处理ACK,交给接收端返回给上层.实际的TCP协议并不是完全的类似于GBN和SR,具体的差异就在ACK的数据是相互传递的,换句话说就是连着兼有.
代码语言:javascript复制void TCPConnection::segment_received(const TCPSegment &seg) {
DUMMY_CODE(seg);
// get the segment from IP level;
if(!_active){
return;
}
_time_since_last_segment_received=0;
//not get segment no send ACK.
//passive connection...
//the ackno is null and no bytes is sent
if(!_receiver.ackno().has_value()&&_sender.next_seqno_absolute()==0){
//only recieve syn...
if(!seg.header().syn) return;
//as the Service side,passive connected.
_receiver.segment_received(seg);
//it's OK to connect.
connect();
return;
}
// active connected..
// first connection...
if(_sender.next_seqno_absolute() > 0 && _sender.bytes_in_flight() == _sender.next_seqno_absolute() &&
!_receiver.ackno().has_value()){
// the length of payload is not 0
if(seg.payload().size() ){
return;
}
// if ack is no
// the twoside wants to setup the connection at the same time.
if(!seg.header().ack){
if(seg.header().syn){
_receiver.segment_received(seg);
// send empty ack to setup the connection.
_sender.send_empty_segment();
}
return;
}
// ifsyn=1,ack=1,rst=1,then shut down.
if(seg.header().rst){
_receiver.stream_out().set_error();
_sender.stream_in().set_error();
_active = false;
return;
}
}
//otherwise...
//recieve the segment
_receiver.segment_received(seg);
_sender.ack_received(seg.header().ackno,seg.header().win);
// thrid connection
if (_sender.stream_in().buffer_empty() && seg.length_in_sequence_space())
_sender.send_empty_segment();
if (seg.header().rst) {
_sender.send_empty_segment();
unclean_shutdown();
return;
}
send_sender_segments();
}
2、写seg.
将上层应用的数据写入到Bytestream中,提醒发送方发送.
代码语言:javascript复制size_t TCPConnection::write(const string &data) {
DUMMY_CODE(data);
// get the OS data... ready to be sent by TCP
if(data.size()==0){
return 0;
}
size_t write_size = _sender.stream_in().write(data);
_sender.fill_window();
send_sender_segments();
return write_size;
}
3、时钟(操作系统不定期调用之)
提醒Sender处理时间,看看是不是超时了.记录一下time_since_last_segment_received.
代码语言:javascript复制//! param[in] ms_since_last_tick number of milliseconds since the last call to this method
void TCPConnection::tick(const size_t ms_since_last_tick) {
DUMMY_CODE(ms_since_last_tick);
if(!_active) return;
//count
_time_since_last_segment_received = ms_since_last_tick;
// tell the sender to tick
_sender.tick(ms_since_last_tick);
if(_sender.consecutive_retransmissions()>TCPConfig::MAX_RETX_ATTEMPTS){
unclean_shutdown();
}
send_sender_segments();
}
4、真正的发送信息:读取sender中的消息缓存,然后加上ack和窗口信息信息,发送出去.
代码语言:javascript复制void TCPConnection::send_sender_segments (){
//travel the queue to set the ack and windows size.
while(!_sender.segments_out().empty()){
TCPSegment seg = _sender.segments_out().front();
_sender.segments_out().pop();
// the ack number is bot null
if(_receiver.ackno().has_value()){
seg.header().ack=true;
seg.header().ackno=_receiver.ackno().value();
seg.header().win=_receiver.window_size();
}
_segments_out.push(seg);
}
//every time send segment,we need to shutdown.
clean_shutdown();
}