计算机网络实验 Go Back N 滑动窗口协议 C++

环境 : Microsoft Visual C++ 6.0

Go Back N 协议  ( 暂无 ack )

#include <iostream>
#include <cstring>
#include "protocol.h"
#include "datalink.h"
using namespace std  ;
#pragma comment ( lib  , "Protocol.lib" )
#define rep ( i , j , n ) for ( int i = int(j) ; i < int(n) ; ++i )
// 帧类型
#define FRAME_DATA 1
#define FRAME_ACK  2
// 窗口大小定义
#define MAX_SEQ 7  
// 超时规定   
#define DATA_TIMER  1200        
// 帧数据结构定义

namespace YHL {
    class FRAME { 
    public:
        unsigned char type ;            // 种类
        unsigned char ack ;             // ack
        unsigned char seq ;             // 序号
        unsigned char data[PKT_LEN] ;   // 数据部分
        unsigned int  padding ; 
    public:
        FRAME () {}
        FRAME ( unsigned char _seq , unsigned char _ack )
            : seq ( _seq )
            , ack ( _ack ) 
        {}
    } One ;    // One 作为反复使用的帧
    
    // 事件参数
    int arg = 0 ;   
    // 物理层是否准备好了              
    int phl_ready = 0 ; 
    // 发送方的左边界    
    unsigned char ack_expected = 0 ;
    // 发送方的右边界 + 1
    unsigned char next_frame_to_send = 0 ;
    // 接受窗口正在移动的号
    unsigned char frame_expected = 0 ;
    // 发送窗口的数量
    unsigned char nbuffered = 0 ;
    // 存储发送窗口
    unsigned char out_buf[MAX_SEQ+1][PKT_LEN] ;
    // 令窗口滑动, 不超过 MAX_SEQ
    unsigned char Go_On ( unsigned char &NO ) {
        return NO = ( NO + 1 ) % ( MAX_SEQ + 1 ) ;
    }        
    // 判断 ack 是否落在发送窗口内
    int between ( unsigned char a , unsigned char b , unsigned char c ) {
        return ( ( ( a <= b ) && ( b < c ) ) 
              || ( ( c < a ) && ( a <= b ) ) 
              || ( ( b < c ) && ( c < a ) ) ) ;
    }
    // 添加 CRC 校验, 发往物理层
    void Add_Crc_and_Send ( unsigned char *frame , int len ) { 
        *(unsigned int *)( frame + len ) = crc32 ( frame , len ) ;
        send_frame ( frame , len + 4 ) ;
        phl_ready = 0 ;
    }
    // 发送一个数据帧
    void Send_Data_Frame ( unsigned char frame_nr , 
                unsigned char frame_expected ) {
        int ack = ( frame_expected + MAX_SEQ ) % ( MAX_SEQ + 1 ) ;
        FRAME One ( frame_nr , ack ) ;
        // 根据序号 frame_nr 获取要发送的数据字段
        memcpy ( One.data , out_buf[frame_nr] , PKT_LEN ) ;
        dbg_frame ( "Send DATA %d %d , ID %d\n" , One.seq , One.ack , *(short *)One.data ) ;
        Add_Crc_and_Send ( (unsigned char *)&One , 3 + PKT_LEN ) ; 
        start_timer ( frame_nr % MAX_SEQ , DATA_TIMER ) ;             
    }
    // 网络层准备好了
    void Net_Layer_OK ()  {
        ++nbuffered ;                
        get_packet ( out_buf[next_frame_to_send] ) ;
        Send_Data_Frame ( next_frame_to_send , frame_expected ) ;
        Go_On ( next_frame_to_send ) ;
    }
    // 收到一个数据帧
    void Recieve_Data () {
        // 先进行校验
        int len = recv_frame ( (unsigned char *)&One , sizeof One ) ;
        if ( len < 5 || crc32 ( (unsigned char *)&One , len ) ) {
            dbg_frame ( "Recv Bad packet\n" ) ;
            return ;
        }
        // 如果的确是接收窗口当前的序号
        if ( One.seq == frame_expected ) {
            dbg_frame ( "Recv DATA %d %d , ID %d\n" , One.seq , One.ack , *(short *)One.data ) ; 
            put_packet ( One.data , len - 7 ) ; // 减去七位非数据位
            Go_On ( frame_expected ) ;
        }
        // 看是否可以腾出发送窗口的左边
        while ( between ( ack_expected , One.ack , next_frame_to_send ) ) {
            --nbuffered ;
            stop_timer ( ack_expected ) ;
            Go_On ( ack_expected ) ;
        }
    }
    // 协议初始化
    void Init_Protocol ( int argc , char **argv ) {
        protocol_init ( argc , argv ) ;
        lprintf ( "Fluence_YHL : " __DATE__"  "__TIME__"\n" ) ;
        disable_network_layer () ;
    }
    // 如果 ack 超时了
    void Data_Time_Out () {
        dbg_event ( "---- DATA %d timeout\n" , arg ) ;  
        // 要传的下一帧是 ack_expected, 也就是左边界     
        next_frame_to_send = ack_expected ;
        for ( int i = 1 ; i <= nbuffered ; ++i ) {
            Send_Data_Frame ( next_frame_to_send , frame_expected ) ;
            Go_On ( next_frame_to_send ) ;
        }
    }
    // 控制网络层开闭
    void Enable_Net_Layer () {
        if ( nbuffered < MAX_SEQ && phl_ready )
            enable_network_layer() ;
        else
            disable_network_layer() ;
    }
    // 获取一个事件
    int Get_event () {
        return wait_for_event ( &arg ) ;
    }
}

int main ( int argc , char **argv ) {
    YHL::Init_Protocol ( argc , argv ) ;
    while ( true ) {
        // 获取一个事件
        int event = YHL::Get_event () ;
        switch ( event ) {
            // 网络层准备好了
            case NETWORK_LAYER_READY : YHL::Net_Layer_OK () ; break ;
            // 收到一个帧
            case FRAME_RECEIVED : YHL::Recieve_Data () ; break ;
            // 物理层准备好了
            case PHYSICAL_LAYER_READY : YHL::phl_ready = 1 ; break ;
            // 超时重发
            case DATA_TIMEOUT : YHL::Data_Time_Out () ; break ;
            // 
            default : break ;
        }
        // 控制网络层流量
        YHL::Enable_Net_Layer () ;
    }
    return 0 ;
}

猜你喜欢

转载自blog.csdn.net/nishisiyuetian/article/details/80275671