在这里我们需要实现一个TCP连接类,在这个TCP连接类里面,我们需要组合之前已经写好的TCP发送端和接收端的函数来进行处理.

1、接受到segment的操作:

分成两种操作,一种是正常的交互,一种是握手的操作.握手又分成主动请求链接和被动链接,在这两种模式下接受握手信息的处理是不一样的.对于正常的交互,需要交付给Sender和Reciever.因为对于TCP来说,两者是相互统一的.两个主机之间也会互相传递信息,所以说交给发送端处理ACK,交给接收端返回给上层.实际的TCP协议并不是完全的类似于GBN和SR,具体的差异就在ACK的数据是相互传递的,换句话说就是连着兼有.

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中,提醒发送方发送.

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.

//! \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和窗口信息信息,发送出去.

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();
}
分类: 测试

0 条评论

发表评论

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用*标注

隐藏